diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index b7b8597a18d..c2870cb1205 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ +github: servo open_collective: servo diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..090cd0c1a7e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,17 @@ +--- +name: Bug Report +about: Create a bug report to help us improve +title: '' +labels: C-untriaged +assignees: '' + +--- + +**Describe the bug:** +A clear and concise description of the bug. + +**To Reproduce:** +Steps to reproduce the behavior. + +**Platform:** +Specify OS, distribution, and hardware platform. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..e48216e8f85 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,11 @@ +--- +name: Feature Request +about: Suggest the implementation of a new feature +title: '' +labels: B-feature-tracking, C-untriaged +assignees: '' + +--- + +**Describe the new feature:** +A clear and concise description of the new feature with links to any relevant specifications. diff --git a/.github/ISSUE_TEMPLATE/security-report.md b/.github/ISSUE_TEMPLATE/security-report.md new file mode 100644 index 00000000000..c6e7535fff0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security-report.md @@ -0,0 +1,17 @@ +--- +name: Security Vulernability +about: Report a security vulnerability +title: '' +labels: A-security, C-untriaged +assignees: '' + +--- + +**Describe the bug:** +A clear and concise description of the vulnerability. + +**To Reproduce:** +Steps to reproduce the behavior. + +**Platform:** +Specify OS, distribution, and hardware platform. diff --git a/.github/workflows/linux-wpt.yml b/.github/workflows/linux-wpt.yml index 85b8a39ad96..1142f357962 100644 --- a/.github/workflows/linux-wpt.yml +++ b/.github/workflows/linux-wpt.yml @@ -70,7 +70,8 @@ jobs: ${{ inputs.wpt-tests-to-run }} \ --${{ inputs.profile }} --processes $(nproc) --timeout-multiplier 2 \ --total-chunks ${{ env.max_chunk_id }} --this-chunk ${{ matrix.chunk_id }} \ - --log-raw wpt-full-logs/linux-${{ inputs.wpt-layout }}/${{ matrix.chunk_id }}.log \ + --log-raw wpt-full-logs/linux-${{ inputs.wpt-layout }}/raw/${{ matrix.chunk_id }}.log \ + --log-wptreport wpt-full-logs/linux-${{ inputs.wpt-layout }}/wptreport/${{ matrix.chunk_id }}.json \ --log-raw-unexpected wpt-filtered-logs/linux-${{ inputs.wpt-layout }}/${{ matrix.chunk_id }}.log \ --filter-intermittents wpt-filtered-logs/linux-${{ inputs.wpt-layout }}/${{ matrix.chunk_id }}.json env: @@ -94,18 +95,19 @@ jobs: if: ${{ always() }} needs: linux-wpt steps: - - name: Merge logs (filtered) - uses: actions/upload-artifact/merge@v4 - with: - name: wpt-filtered-logs-linux-${{ inputs.wpt-layout }} - pattern: wpt-filtered-logs-linux-${{ inputs.wpt-layout }}-* - delete-merged: true - name: Merge logs (full) uses: actions/upload-artifact/merge@v4 with: name: wpt-full-logs-linux-${{ inputs.wpt-layout }} pattern: wpt-full-logs-linux-${{ inputs.wpt-layout }}-* delete-merged: true + # This job needs to be last. If no filtered results were uploaded, it will fail, but we want to merge other archives in that case. + - name: Merge logs (filtered) + uses: actions/upload-artifact/merge@v4 + with: + name: wpt-filtered-logs-linux-${{ inputs.wpt-layout }} + pattern: wpt-filtered-logs-linux-${{ inputs.wpt-layout }}-* + delete-merged: true - uses: actions/checkout@v4 if: ${{ !cancelled() && !inputs.wpt-sync-from-upstream }} - uses: actions/download-artifact@v4 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..9e5df9472c1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,13 @@ +# Code of Conduct + +The Servo Project follows the [**Rust Code of Conduct**](https://www.rust-lang.org/policies/code-of-conduct), with two differences. + +Our code of conduct applies to the [Servo Zulip channels](https://servo.zulipchat.com/), [GitHub repositories](https://github.com/servo), and all official Servo venues, rather than the Rust project. + +If you are subject to or witness unacceptable behavior, or have any other concerns, please notify one of our designated contacts: +* Delan Azabani (she/her) +* Martin Robinson (he/him) +* Manuel Rego Casasnovas (he/him) + +*Note: If you modify this file, please keep this file in sync with .* + diff --git a/Cargo.lock b/Cargo.lock index e1b22896860..bade62af1ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "app_units" @@ -176,7 +176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac57f2b058a76363e357c056e4f74f1945bf734d37b8b3ef49066c4787dde0fc" dependencies = [ "clipboard-win", - "core-graphics", + "core-graphics 0.22.3", "image", "log", "objc", @@ -311,12 +311,6 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -[[package]] -name = "binary-space-partition" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" - [[package]] name = "bincode" version = "1.3.3" @@ -526,18 +520,18 @@ checksum = "28346c117b50270785fbc123bd6e4ecad20d0c6d5f43d081dc80a3abcc62be64" [[package]] name = "bytemuck" -version = "1.14.3" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", @@ -737,7 +731,7 @@ dependencies = [ "block", "cocoa-foundation", "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "foreign-types 0.3.2", "libc", "objc", @@ -924,12 +918,6 @@ dependencies = [ "url", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.12.0" @@ -978,6 +966,19 @@ dependencies = [ "libc", ] +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.1.3" @@ -996,11 +997,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" dependencies = [ "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "foreign-types 0.3.2", "libc", ] +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation", + "core-graphics 0.23.1", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -1101,16 +1114,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "cstr" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "d3d12" version = "0.7.0" @@ -1208,7 +1211,7 @@ dependencies = [ [[package]] name = "derive_common" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "darling", "proc-macro2", @@ -1223,10 +1226,8 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version", "syn 1.0.109", ] @@ -1680,8 +1681,8 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "core-foundation", - "core-graphics", - "core-text", + "core-graphics 0.22.3", + "core-text 19.2.0", "dirs-next", "dwrote", "float-ord", @@ -1951,8 +1952,8 @@ dependencies = [ "bitflags 2.4.2", "byteorder", "core-foundation", - "core-graphics", - "core-text", + "core-graphics 0.22.3", + "core-text 19.2.0", "dwrote", "euclid", "fnv", @@ -2565,8 +2566,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf8c27ca13930dc4ffe474880040fe9e0f03c2121600dc9c95423624cab3e467" dependencies = [ "cc", - "core-graphics", - "core-text", + "core-graphics 0.22.3", + "core-text 19.2.0", "foreign-types 0.3.2", "freetype", "pkg-config", @@ -3304,7 +3305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -3463,7 +3464,7 @@ dependencies = [ [[package]] name = "malloc_size_of" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "accountable-refcell", "app_units", @@ -4229,8 +4230,8 @@ dependencies = [ [[package]] name = "peek-poke" -version = "0.2.0" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.3.0" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ "euclid", "peek-poke-derive", @@ -4238,13 +4239,13 @@ dependencies = [ [[package]] name = "peek-poke-derive" -version = "0.2.1" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.3.0" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "syn 2.0.52", + "synstructure 0.13.1", "unicode-xid", ] @@ -4404,14 +4405,13 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plane-split" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f7075ec146b897b6e0faca47adeb7ed3d4f6eaa8145bf19db17311081b3f63" +checksum = "8c1f7d82649829ecdef8e258790b0587acf0a8403f0ce963473d8e918acc1643" dependencies = [ - "binary-space-partition", "euclid", "log", - "num-traits", + "smallvec", ] [[package]] @@ -4477,9 +4477,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -4928,8 +4928,8 @@ dependencies = [ "parking_lot", "percent-encoding", "phf 0.10.1", - "phf_codegen 0.10.0", - "phf_shared 0.10.0", + "phf_codegen 0.11.2", + "phf_shared 0.11.2", "pixels", "profile_traits", "range", @@ -5075,7 +5075,7 @@ dependencies = [ [[package]] name = "selectors" version = "0.24.0" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "bitflags 1.3.2", "cssparser", @@ -5363,7 +5363,7 @@ dependencies = [ [[package]] name = "servo_arc" version = "0.2.0" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "nodrop", "serde", @@ -5373,7 +5373,7 @@ dependencies = [ [[package]] name = "servo_atoms" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "string_cache", "string_cache_codegen", @@ -5579,7 +5579,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "size_of_test" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "static_assertions", ] @@ -5604,9 +5604,9 @@ dependencies = [ [[package]] name = "smallbitvec" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ce4f9dc4a41b4c3476cc925f1efb11b66df373a8fde5d4b8915fa91b5d995e" +checksum = "89585d5125f6ba10f6aecf290219b36691ca293e9267f1c9575fae0e5cd9c620" [[package]] name = "smallvec" @@ -5705,7 +5705,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "static_prefs" version = "0.1.0" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" [[package]] name = "str-buf" @@ -5748,7 +5748,7 @@ dependencies = [ [[package]] name = "style" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "app_units", "arrayvec", @@ -5806,7 +5806,7 @@ dependencies = [ [[package]] name = "style_config" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "lazy_static", ] @@ -5814,7 +5814,7 @@ dependencies = [ [[package]] name = "style_derive" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "darling", "derive_common", @@ -5845,7 +5845,7 @@ dependencies = [ [[package]] name = "style_traits" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "app_units", "bitflags 1.3.2", @@ -5876,7 +5876,7 @@ dependencies = [ "cgl", "cocoa", "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "euclid", "fnv", "gl_generator", @@ -5961,9 +5961,9 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.2.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +checksum = "e8e9199467bcbc77c6a13cc6e32a6af21721ab8c96aa0261856c4fda5a4433f0" dependencies = [ "cfg-expr", "heck", @@ -6056,18 +6056,18 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -6188,7 +6188,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "to_shmem" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "cssparser", "servo_arc", @@ -6201,7 +6201,7 @@ dependencies = [ [[package]] name = "to_shmem_derive" version = "0.0.1" -source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#3f129fb95a345f0057a6b72901eb7eb795840a76" +source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#7dd884031d6b97d801d50f8fcdff69bbeb292ae0" dependencies = [ "darling", "derive_common", @@ -6330,6 +6330,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "topological-sort" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c" + [[package]] name = "tower-service" version = "0.3.2" @@ -6866,31 +6872,24 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webrender" -version = "0.61.0" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.64.0" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ "bincode", - "bitflags 1.3.2", + "bitflags 2.4.2", "build-parallel", "byteorder", - "core-foundation", - "core-graphics", - "core-text", - "cstr", "derive_more", - "dwrote", "etagere", "euclid", - "freetype", "fxhash", "gleam", "glslopt", "lazy_static", - "libc", "log", "malloc_size_of_derive", "num-traits", - "objc", + "peek-poke", "plane-split", "rayon", "ron", @@ -6898,24 +6897,23 @@ dependencies = [ "smallvec", "svg_fmt", "time 0.1.45", + "topological-sort", "tracy-rs", "webrender_api", "webrender_build", + "wr_glyph_rasterizer", "wr_malloc_size_of", ] [[package]] name = "webrender_api" -version = "0.61.0" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.64.0" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ "app_units", - "bitflags 1.3.2", + "bitflags 2.4.2", "byteorder", - "core-foundation", - "core-graphics", "crossbeam-channel", - "derive_more", "euclid", "malloc_size_of_derive", "peek-poke", @@ -6928,10 +6926,10 @@ dependencies = [ [[package]] name = "webrender_build" -version = "0.0.1" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.0.2" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "lazy_static", ] @@ -7332,7 +7330,7 @@ dependencies = [ "bitflags 1.3.2", "cfg_aliases", "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "dispatch", "instant", "libc", @@ -7384,10 +7382,35 @@ dependencies = [ "winapi", ] +[[package]] +name = "wr_glyph_rasterizer" +version = "0.1.0" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" +dependencies = [ + "core-foundation", + "core-graphics 0.23.1", + "core-text 20.1.0", + "dwrote", + "euclid", + "freetype", + "fxhash", + "lazy_static", + "libc", + "log", + "malloc_size_of_derive", + "objc", + "rayon", + "serde", + "smallvec", + "tracy-rs", + "webrender_api", + "wr_malloc_size_of", +] + [[package]] name = "wr_malloc_size_of" -version = "0.0.1" -source = "git+https://github.com/servo/webrender?rev=f91b68a61#f91b68a616377da0f3f8858f3cead3e47da4acdd" +version = "0.0.2" +source = "git+https://github.com/servo/webrender?branch=0.64#9d354adf8955b1390dd56db89e6d5a9ea7880391" dependencies = [ "app_units", "euclid", diff --git a/Cargo.toml b/Cargo.toml index 17e2aefb1d5..2b86c25f1f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ servo-media-gstreamer = { git = "https://github.com/servo/media" } servo_arc = { git = "https://github.com/servo/stylo.git", branch = "2023-07-23" } servo_atoms = { git = "https://github.com/servo/stylo.git", branch = "2023-07-23" } size_of_test = { git = "https://github.com/servo/stylo.git", branch = "2023-07-23" } -smallbitvec = "2.3.0" +smallbitvec = "2.5.2" smallvec = "1.13" sparkle = "0.1.26" string_cache = "0.8" @@ -123,8 +123,8 @@ uuid = { version = "1.7.0", features = ["v4"] } webdriver = "0.49.0" webpki = "0.22" webpki-roots = "0.25" -webrender = { git = "https://github.com/servo/webrender", rev = "f91b68a61", features = ["capture"] } -webrender_api = { git = "https://github.com/servo/webrender", rev = "f91b68a61" } +webrender = { git = "https://github.com/servo/webrender", branch = "0.64", features = ["capture"] } +webrender_api = { git = "https://github.com/servo/webrender", branch = "0.64" } webrender_traits = { path = "components/shared/webrender" } wgpu-core = "0.18" wgpu-types = "0.18" diff --git a/README.md b/README.md index cdd3f52a5e9..585915de242 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ See also [Windows Troubleshooting Tips][windows-tips]. - Install the latest version of the [Android command-line tools](https://developer.android.com/studio#command-tools) to `$ANDROID_SDK_ROOT/cmdline-tools/latest`. -- Run the following command to install the necessary components and the path t +- Run the following command to install the necessary components: ```shell sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "build-tools;33.0.2" \ @@ -187,7 +187,10 @@ Run Servo with the command: #### Linux * `GStreamer` >=1.18 +* `gst-plugins-base` >=1.18 +* `gst-plugins-good` >=1.18 * `gst-plugins-bad` >=1.18 +* `gst-plugins-ugly` >=1.18 * `libXcursor` * `libXrandr` * `libXi` @@ -204,4 +207,4 @@ The generated documentation can be found on https://doc.servo.org/servo/index.ht [manual-build]: https://github.com/servo/servo/wiki/Building#manual-build-setup [windows-tips]: https://github.com/servo/servo/wiki/Building#troubleshooting-the-windows-build -[android-docs]: https://github.com/servo/servo/wiki/Android +[android-docs]: https://github.com/servo/servo/wiki/Building-for-Android diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..a4b32316542 --- /dev/null +++ b/SECURITY.md @@ -0,0 +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/issues/new) for now. + diff --git a/components/allocator/lib.rs b/components/allocator/lib.rs index f6cf47eada5..20ac30e8022 100644 --- a/components/allocator/lib.rs +++ b/components/allocator/lib.rs @@ -13,11 +13,13 @@ pub use crate::platform::*; mod platform { use std::os::raw::c_void; - use jemallocator; - - pub use self::jemallocator::Jemalloc as Allocator; + pub use jemallocator::Jemalloc as Allocator; /// Get the size of a heap block. + /// + /// # Safety + /// + /// Passing a non-heap allocated pointer to this function results in undefined behavior. pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize { jemallocator::usable_size(ptr) } @@ -37,12 +39,16 @@ mod platform { use std::os::raw::c_void; /// Get the size of a heap block. + /// + /// # Safety + /// + /// Passing a non-heap allocated pointer to this function results in undefined behavior. pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize { - #[cfg(target_os = "linux")] - return libc::malloc_usable_size(ptr as *mut _); + #[cfg(target_vendor = "apple")] + return libc::malloc_size(ptr); - #[cfg(not(target_os = "linux"))] - return libc::malloc_usable_size(ptr); + #[cfg(not(target_vendor = "apple"))] + return libc::malloc_usable_size(ptr as *mut _); } pub mod libc_compat { @@ -58,6 +64,10 @@ mod platform { use winapi::um::heapapi::{GetProcessHeap, HeapSize, HeapValidate}; /// Get the size of a heap block. + /// + /// # Safety + /// + /// Passing a non-heap allocated pointer to this function results in undefined behavior. pub unsafe extern "C" fn usable_size(mut ptr: *const c_void) -> usize { let heap = GetProcessHeap(); diff --git a/components/background_hang_monitor/background_hang_monitor.rs b/components/background_hang_monitor/background_hang_monitor.rs index 1aacadfa19a..e57cf4b4f11 100644 --- a/components/background_hang_monitor/background_hang_monitor.rs +++ b/components/background_hang_monitor/background_hang_monitor.rs @@ -49,6 +49,7 @@ impl HangMonitorRegister { let (tether, tether_port) = unbounded(); let _ = thread::Builder::new() + .name("BackgroundHangMonitor".to_owned()) .spawn(move || { let mut monitor = BackgroundHangMonitorWorker::new( constellation_chan, @@ -92,19 +93,19 @@ impl BackgroundHangMonitorRegister for HangMonitorRegister { target_os = "windows", any(target_arch = "x86_64", target_arch = "x86") ))] - let sampler = crate::sampler_windows::WindowsSampler::new(); + let sampler = crate::sampler_windows::WindowsSampler::new_boxed(); #[cfg(target_os = "macos")] - let sampler = crate::sampler_mac::MacOsSampler::new(); + let sampler = crate::sampler_mac::MacOsSampler::new_boxed(); #[cfg(all( target_os = "linux", not(any(target_arch = "arm", target_arch = "aarch64")) ))] - let sampler = crate::sampler_linux::LinuxSampler::new(); + let sampler = crate::sampler_linux::LinuxSampler::new_boxed(); #[cfg(any( target_os = "android", all(target_os = "linux", any(target_arch = "arm", target_arch = "aarch64")) ))] - let sampler = crate::sampler::DummySampler::new(); + let sampler = crate::sampler::DummySampler::new_boxed(); // When a component is registered, and there's an exit request that // reached BHM, we want an exit signal to be delivered to the @@ -208,7 +209,7 @@ impl BackgroundHangMonitorChan { BackgroundHangMonitorChan { sender, _tether: tether, - component_id: component_id, + component_id, disconnected: Default::default(), monitoring_enabled, } @@ -312,14 +313,14 @@ struct BackgroundHangMonitorWorker { monitoring_enabled: bool, } +type MonitoredComponentSender = Sender<(MonitoredComponentId, MonitoredComponentMsg)>; +type MonitoredComponentReceiver = Receiver<(MonitoredComponentId, MonitoredComponentMsg)>; + impl BackgroundHangMonitorWorker { fn new( constellation_chan: IpcSender, control_port: IpcReceiver, - (port_sender, port): ( - Arc>, - Receiver<(MonitoredComponentId, MonitoredComponentMsg)>, - ), + (port_sender, port): (Arc, MonitoredComponentReceiver), tether_port: Receiver, monitoring_enabled: bool, ) -> Self { @@ -360,7 +361,7 @@ impl BackgroundHangMonitorWorker { let profile = stack.to_hangprofile(); let name = match self.component_names.get(&id) { Some(ref s) => format!("\"{}\"", s), - None => format!("null"), + None => "null".to_string(), }; let json = format!( "{}{{ \"name\": {}, \"namespace\": {}, \"index\": {}, \"type\": \"{:?}\", \ @@ -389,12 +390,10 @@ impl BackgroundHangMonitorWorker { .checked_sub(Instant::now() - self.last_sample) .unwrap_or_else(|| Duration::from_millis(0)); after(duration) + } else if self.monitoring_enabled { + after(Duration::from_millis(100)) } else { - if self.monitoring_enabled { - after(Duration::from_millis(100)) - } else { - never() - } + never() }; let received = select! { @@ -403,13 +402,8 @@ impl BackgroundHangMonitorWorker { // gets disconnected. Some(event.unwrap()) }, - recv(self.tether_port) -> event => { + recv(self.tether_port) -> _ => { // This arm can only reached by a tether disconnection - match event { - Ok(x) => match x {} - Err(_) => {} - } - // All associated `HangMonitorRegister` and // `BackgroundHangMonitorChan` have been dropped. Suppress // `signal_to_exit` and exit the BHM. diff --git a/components/background_hang_monitor/sampler.rs b/components/background_hang_monitor/sampler.rs index 593401a08a5..82f6b7e0fde 100644 --- a/components/background_hang_monitor/sampler.rs +++ b/components/background_hang_monitor/sampler.rs @@ -4,7 +4,6 @@ use std::ptr; -use backtrace; use msg::constellation_msg::{HangProfile, HangProfileSymbol}; const MAX_NATIVE_FRAMES: usize = 1024; @@ -18,7 +17,7 @@ pub struct DummySampler; impl DummySampler { #[allow(dead_code)] - pub fn new() -> Box { + pub fn new_boxed() -> Box { Box::new(DummySampler) } } @@ -64,12 +63,12 @@ impl NativeStack { instruction_ptr: *mut std::ffi::c_void, stack_ptr: *mut std::ffi::c_void, ) -> Result<(), ()> { - if !(self.count < MAX_NATIVE_FRAMES) { + if self.count >= MAX_NATIVE_FRAMES { return Err(()); } self.instruction_ptrs[self.count] = instruction_ptr; self.stack_ptrs[self.count] = stack_ptr; - self.count = self.count + 1; + self.count += 1; Ok(()) } @@ -85,7 +84,7 @@ impl NativeStack { // TODO: use the demangled or C++ demangled symbols if available. let name = symbol .name() - .map(|n| String::from_utf8_lossy(&n.as_bytes()).to_string()); + .map(|n| String::from_utf8_lossy(n.as_bytes()).to_string()); let filename = symbol.filename().map(|n| n.to_string_lossy().to_string()); let lineno = symbol.lineno(); profile.backtrace.push(HangProfileSymbol { diff --git a/components/background_hang_monitor/sampler_linux.rs b/components/background_hang_monitor/sampler_linux.rs index b24edac3356..b392e49b06d 100644 --- a/components/background_hang_monitor/sampler_linux.rs +++ b/components/background_hang_monitor/sampler_linux.rs @@ -6,9 +6,8 @@ use std::cell::UnsafeCell; use std::sync::atomic::{AtomicPtr, Ordering}; -use std::{io, mem, process, ptr, thread}; +use std::{cmp, io, mem, process, ptr, thread}; -use libc; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; use unwind_sys::{ unw_cursor_t, unw_get_reg, unw_init_local, unw_step, UNW_ESUCCESS, UNW_REG_IP, UNW_REG_SP, @@ -138,7 +137,7 @@ pub struct LinuxSampler { impl LinuxSampler { #[allow(unsafe_code, dead_code)] - pub fn new() -> Box { + pub fn new_boxed() -> Box { let thread_id = unsafe { libc::syscall(libc::SYS_gettid) as libc::pid_t }; let handler = SigHandler::SigAction(sigprof_handler); let action = SigAction::new( @@ -181,12 +180,10 @@ fn step(cursor: *mut unw_cursor_t) -> Result { } let ret = unw_step(cursor); - if ret > 0 { - Ok(true) - } else if ret == 0 { - Ok(false) - } else { - Err(ret) + match ret.cmp(&0) { + cmp::Ordering::Less => Err(ret), + cmp::Ordering::Greater => Ok(true), + cmp::Ordering::Equal => Ok(false), } } } @@ -222,6 +219,7 @@ impl Sampler for LinuxSampler { let ret = unsafe { unw_init_local(cursor.as_mut_ptr(), context) }; result = if ret == UNW_ESUCCESS { let mut native_stack = NativeStack::new(); + #[allow(clippy::while_let_loop)] // False positive loop { let ip = match get_register(cursor.as_mut_ptr(), RegNum::Ip) { Ok(ip) => ip, diff --git a/components/background_hang_monitor/sampler_mac.rs b/components/background_hang_monitor/sampler_mac.rs index ed85ef8d904..d870435b196 100644 --- a/components/background_hang_monitor/sampler_mac.rs +++ b/components/background_hang_monitor/sampler_mac.rs @@ -4,8 +4,6 @@ use std::{panic, process}; -use {libc, mach2}; - use crate::sampler::{Address, NativeStack, Registers, Sampler}; type MonitoredThreadId = mach2::mach_types::thread_act_t; @@ -16,7 +14,7 @@ pub struct MacOsSampler { impl MacOsSampler { #[allow(unsafe_code)] - pub fn new() -> Box { + pub fn new_boxed() -> Box { let thread_id = unsafe { mach2::mach_init::mach_thread_self() }; Box::new(MacOsSampler { thread_id }) } diff --git a/components/background_hang_monitor/sampler_windows.rs b/components/background_hang_monitor/sampler_windows.rs index cbc88d42156..ed3b58cca1b 100644 --- a/components/background_hang_monitor/sampler_windows.rs +++ b/components/background_hang_monitor/sampler_windows.rs @@ -13,7 +13,7 @@ pub struct WindowsSampler { impl WindowsSampler { #[allow(unsafe_code, dead_code)] - pub fn new() -> Box { + pub fn new_boxed() -> Box { let thread_id = 0; // TODO: use winapi::um::processthreadsapi::GetThreadId Box::new(WindowsSampler { thread_id }) } diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 477d08d328c..b125eb4e65c 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -74,23 +74,23 @@ impl PathState { pub trait Backend { fn get_composition_op(&self, opts: &DrawOptions) -> CompositionOp; fn need_to_draw_shadow(&self, color: &Color) -> bool; - fn set_shadow_color<'a>(&mut self, color: RGBA, state: &mut CanvasPaintState<'a>); - fn set_fill_style<'a>( + fn set_shadow_color(&mut self, color: RGBA, state: &mut CanvasPaintState<'_>); + fn set_fill_style( &mut self, style: FillOrStrokeStyle, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, drawtarget: &dyn GenericDrawTarget, ); - fn set_stroke_style<'a>( + fn set_stroke_style( &mut self, style: FillOrStrokeStyle, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, drawtarget: &dyn GenericDrawTarget, ); - fn set_global_composition<'a>( + fn set_global_composition( &mut self, op: CompositionOrBlending, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, ); fn create_drawtarget(&self, size: Size2D) -> Box; fn recreate_paint_state<'a>(&self, state: &CanvasPaintState<'a>) -> CanvasPaintState<'a>; @@ -114,6 +114,7 @@ pub trait GenericPathBuilder { control_point3: &Point2D, ); fn close(&mut self); + #[allow(clippy::too_many_arguments)] fn ellipse( &mut self, origin: Point2D, @@ -195,6 +196,7 @@ impl<'a> PathBuilderRef<'a> { .arc(center, radius, start_angle, end_angle, ccw); } + #[allow(clippy::too_many_arguments)] pub fn ellipse( &mut self, center: &Point2D, @@ -222,10 +224,9 @@ impl<'a> PathBuilderRef<'a> { Some(i) => i, None => return None, }; - match self.builder.get_current_point() { - Some(point) => Some(inverse.transform_point(Point2D::new(point.x, point.y))), - None => None, - } + self.builder + .get_current_point() + .map(|point| inverse.transform_point(Point2D::new(point.x, point.y))) } fn close(&mut self) { @@ -428,7 +429,7 @@ impl<'a> CanvasData<'a> { let source_rect = source_rect.ceil(); // It discards the extra pixels (if any) that won't be painted let image_data = if Rect::from_size(image_size).contains_rect(&source_rect) { - pixels::rgba8_get_rect(&image_data, image_size.to_u64(), source_rect.to_u64()).into() + pixels::rgba8_get_rect(image_data, image_size.to_u64(), source_rect.to_u64()).into() } else { image_data.into() }; @@ -493,15 +494,14 @@ impl<'a> CanvasData<'a> { let font = font_style.map_or_else( || load_system_font_from_style(None), |style| { - with_thread_local_font_context(&self, |font_context| { + with_thread_local_font_context(self, |font_context| { let font_group = font_context.font_group(ServoArc::new(style.clone())); let font = font_group .borrow_mut() .first(font_context) .expect("couldn't find font"); let font = font.borrow_mut(); - let template = font.handle.template(); - Font::from_bytes(Arc::new(template.bytes()), 0) + Font::from_bytes(font.handle.template().bytes(), 0) .ok() .or_else(|| load_system_font_from_style(Some(style))) }) @@ -651,7 +651,7 @@ impl<'a> CanvasData<'a> { } if self.need_to_draw_shadow() { - self.draw_with_shadow(&rect, |new_draw_target: &mut dyn GenericDrawTarget| { + self.draw_with_shadow(rect, |new_draw_target: &mut dyn GenericDrawTarget| { new_draw_target.stroke_rect( rect, self.state.stroke_style.clone(), @@ -918,7 +918,7 @@ impl<'a> CanvasData<'a> { Some(p) => p, None => { self.path_builder().move_to(cp1); - cp1.clone() + *cp1 }, }; let cp1 = *cp1; @@ -979,6 +979,7 @@ impl<'a> CanvasData<'a> { } } + #[allow(clippy::too_many_arguments)] pub fn ellipse( &mut self, center: &Point2D, @@ -1042,7 +1043,7 @@ impl<'a> CanvasData<'a> { } }, } - self.state.transform = transform.clone(); + self.state.transform = *transform; self.drawtarget.set_transform(transform) } @@ -1200,10 +1201,7 @@ impl<'a> CanvasData<'a> { draw_shadow_source(&mut *new_draw_target); self.drawtarget.draw_surface_with_shadow( new_draw_target.snapshot(), - &Point2D::new( - shadow_src_rect.origin.x as f32, - shadow_src_rect.origin.y as f32, - ), + &Point2D::new(shadow_src_rect.origin.x, shadow_src_rect.origin.y), &self.state.shadow_color, &Vector2D::new( self.state.shadow_offset_x as f32, @@ -1394,18 +1392,18 @@ fn load_system_font_from_style(font_style: Option<&FontStyleStruct>) -> Option handle, Err(e) => { error!("error getting font handle for style {:?}: {}", style, e); - return load_default_system_fallback_font(&properties); + return load_default_system_fallback_font(properties); }, }; match font_handle.load() { Ok(f) => Some(f), Err(e) => { error!("error loading font for style {:?}: {}", style, e); - load_default_system_fallback_font(&properties) + load_default_system_fallback_font(properties) }, } } diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 808714b14e8..17b5fb762fe 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -130,7 +130,7 @@ impl<'a> CanvasPaintThread<'a> { let font_cache_thread = self.font_cache_thread.clone(); - let canvas_id = self.next_canvas_id.clone(); + let canvas_id = self.next_canvas_id; self.next_canvas_id.0 += 1; let canvas_data = CanvasData::new( @@ -139,7 +139,7 @@ impl<'a> CanvasPaintThread<'a> { antialias, font_cache_thread, ); - self.canvases.insert(canvas_id.clone(), canvas_data); + self.canvases.insert(canvas_id, canvas_data); canvas_id } @@ -181,7 +181,7 @@ impl<'a> CanvasPaintThread<'a> { source_rect, smoothing_enabled, ) => self.canvas(canvas_id).draw_image( - &*image_data, + image_data, image_size, dest_rect, source_rect, diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index 36e0de9351b..aa3737897eb 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -29,14 +29,14 @@ impl Backend for RaqoteBackend { color.as_raqote().a != 0 } - fn set_shadow_color<'a>(&mut self, color: RGBA, state: &mut CanvasPaintState<'a>) { + fn set_shadow_color(&mut self, color: RGBA, state: &mut CanvasPaintState<'_>) { state.shadow_color = Color::Raqote(color.to_raqote_style()); } - fn set_fill_style<'a>( + fn set_fill_style( &mut self, style: FillOrStrokeStyle, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, _drawtarget: &dyn GenericDrawTarget, ) { if let Some(pattern) = style.to_raqote_pattern() { @@ -44,10 +44,10 @@ impl Backend for RaqoteBackend { } } - fn set_stroke_style<'a>( + fn set_stroke_style( &mut self, style: FillOrStrokeStyle, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, _drawtarget: &dyn GenericDrawTarget, ) { if let Some(pattern) = style.to_raqote_pattern() { @@ -55,10 +55,10 @@ impl Backend for RaqoteBackend { } } - fn set_global_composition<'a>( + fn set_global_composition( &mut self, op: CompositionOrBlending, - state: &mut CanvasPaintState<'a>, + state: &mut CanvasPaintState<'_>, ) { state.draw_options.as_raqote_mut().blend_mode = op.to_raqote_style(); } @@ -125,9 +125,9 @@ pub struct LinearGradientPattern { impl LinearGradientPattern { fn new(start: Point2D, end: Point2D, stops: Vec) -> Self { LinearGradientPattern { - gradient: raqote::Gradient { stops: stops }, - start: start, - end: end, + gradient: raqote::Gradient { stops }, + start, + end, } } } @@ -150,11 +150,11 @@ impl RadialGradientPattern { stops: Vec, ) -> Self { RadialGradientPattern { - gradient: raqote::Gradient { stops: stops }, - center1: center1, - radius1: radius1, - center2: center2, - radius2: radius2, + gradient: raqote::Gradient { stops }, + center1, + radius1, + center2, + radius2, } } } @@ -177,10 +177,10 @@ impl<'a> SurfacePattern<'a> { }, }; SurfacePattern { - image: image, - filter: filter, - extend: extend, - repeat: repeat, + image, + filter, + extend, + repeat, transform: Transform2D::identity(), } } @@ -389,7 +389,7 @@ impl GenericDrawTarget for raqote::DrawTarget { fn create_gradient_stops(&self, gradient_stops: Vec) -> GradientStops { let mut stops = gradient_stops .into_iter() - .map(|item| item.as_raqote().clone()) + .map(|item| *item.as_raqote()) .collect::>(); // https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap()); @@ -492,7 +492,7 @@ impl GenericDrawTarget for raqote::DrawTarget { raqote::BlendMode::SrcOut | raqote::BlendMode::DstIn | raqote::BlendMode::DstAtop => { - let mut options = draw_options.as_raqote().clone(); + let mut options = *draw_options.as_raqote(); self.push_layer_with_blend(1., options.blend_mode); options.blend_mode = raqote::BlendMode::SrcOver; self.fill(path.as_raqote(), &pattern.source(), &options); @@ -654,28 +654,23 @@ impl GenericDrawTarget for raqote::DrawTarget { #[allow(unsafe_code)] fn snapshot_data(&self, f: &dyn Fn(&[u8]) -> Vec) -> Vec { let v = self.get_data(); - f(unsafe { - std::slice::from_raw_parts( - v.as_ptr() as *const u8, - v.len() * std::mem::size_of::(), - ) - }) + f( + unsafe { + std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) + }, + ) } #[allow(unsafe_code)] fn snapshot_data_owned(&self) -> Vec { let v = self.get_data(); unsafe { - std::slice::from_raw_parts( - v.as_ptr() as *const u8, - v.len() * std::mem::size_of::(), - ) - .into() + std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)).into() } } } impl Filter { - fn to_raqote(&self) -> raqote::FilterMode { + fn to_raqote(self) -> raqote::FilterMode { match self { Filter::Bilinear => raqote::FilterMode::Bilinear, Filter::Nearest => raqote::FilterMode::Nearest, @@ -852,7 +847,7 @@ pub trait ToRaqotePattern<'a> { } pub trait ToRaqoteGradientStop { - fn to_raqote(&self) -> raqote::GradientStop; + fn to_raqote(self) -> raqote::GradientStop; } /// Clamp a 0..1 number to a 0..255 range to u8. @@ -883,7 +878,7 @@ pub fn clamp_floor_256_f32(val: f32) -> u8 { } impl ToRaqoteGradientStop for CanvasGradientStop { - fn to_raqote(&self) -> raqote::GradientStop { + fn to_raqote(self) -> raqote::GradientStop { let color = raqote::Color::new( self.color.alpha.map(clamp_unit_f32).unwrap_or(0), self.color.red.unwrap_or(0), @@ -895,7 +890,7 @@ impl ToRaqoteGradientStop for CanvasGradientStop { } } -impl<'a> ToRaqotePattern<'_> for FillOrStrokeStyle { +impl ToRaqotePattern<'_> for FillOrStrokeStyle { #[allow(unsafe_code)] fn to_raqote_pattern(self) -> Option> { use canvas_traits::canvas::FillOrStrokeStyle::*; diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index ba9cee6ac02..fba01b39411 100644 --- a/components/canvas/webgl_mode/inprocess.rs +++ b/components/canvas/webgl_mode/inprocess.rs @@ -65,7 +65,7 @@ impl WebGLComm { WebGLComm { webgl_threads: WebGLThreads(sender), image_handler: Box::new(external), - webxr_layer_grand_manager: webxr_layer_grand_manager, + webxr_layer_grand_manager, } } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 656ca35a463..835056591d3 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -289,7 +289,7 @@ impl WebGLThread { let exit = self.handle_msg(msg, &webgl_chan); if exit { // Call remove_context functions in order to correctly delete WebRender image keys. - let context_ids: Vec = self.contexts.keys().map(|id| *id).collect(); + let context_ids: Vec = self.contexts.keys().copied().collect(); for id in context_ids { self.remove_webgl_context(id); } @@ -323,7 +323,7 @@ impl WebGLThread { &mut self.bound_context_id, ) .expect("WebGLContext not found"); - let glsl_version = Self::get_glsl_version(&*data.gl); + let glsl_version = Self::get_glsl_version(&data.gl); let api_type = match data.gl.get_type() { gl::GlType::Gl => GlType::Gl, gl::GlType::Gles => GlType::Gles, @@ -458,7 +458,7 @@ impl WebGLThread { WebGLImpl::apply( &self.device, &data.ctx, - &*data.gl, + &data.gl, &mut data.state, &data.attributes, command, @@ -497,12 +497,12 @@ impl WebGLThread { ContextAttributeFlags::STENCIL; let context_attributes = &ContextAttributes { version: webgl_version.to_surfman_version(self.api_type), - flags: flags, + flags, }; let context_descriptor = self .device - .create_context_descriptor(&context_attributes) + .create_context_descriptor(context_attributes) .map_err(|err| format!("Failed to create context descriptor: {:?}", err))?; let safe_size = Size2D::new( @@ -562,7 +562,7 @@ impl WebGLThread { })), }; - let limits = GLLimits::detect(&*gl, webgl_version); + let limits = GLLimits::detect(&gl, webgl_version); let size = clamp_viewport(&gl, requested_size); if safe_size != size { @@ -583,7 +583,7 @@ impl WebGLThread { .device .context_surface_info(&ctx) .map_err(|err| format!("Failed to get context surface info: {:?}", err))? - .ok_or_else(|| format!("Failed to get context surface info"))? + .ok_or_else(|| "Failed to get context surface info".to_string())? .framebuffer_object; gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer); @@ -616,7 +616,7 @@ impl WebGLThread { }; debug!("Created state {:?}", state); - state.restore_invariant(&*gl); + state.restore_invariant(&gl); debug_assert_eq!(gl.get_error(), gl::NO_ERROR); self.contexts.insert( @@ -663,7 +663,7 @@ impl WebGLThread { // Check to see if any of the current framebuffer bindings are the surface we're about to // throw out. If so, we'll have to reset them after destroying the surface. let framebuffer_rebinding_info = - FramebufferRebindingInfo::detect(&self.device, &data.ctx, &*data.gl); + FramebufferRebindingInfo::detect(&self.device, &data.ctx, &data.gl); // Resize the swap chains if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) { @@ -676,14 +676,14 @@ impl WebGLThread { .resize(&mut self.device, &mut data.ctx, size.to_i32()) .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?; swap_chain - .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color) + .clear_surface(&mut self.device, &mut data.ctx, &data.gl, clear_color) .map_err(|err| format!("Failed to clear resized swap chain: {:?}", err))?; } else { error!("Failed to find swap chain"); } // Reset framebuffer bindings as appropriate. - framebuffer_rebinding_info.apply(&self.device, &data.ctx, &*data.gl); + framebuffer_rebinding_info.apply(&self.device, &data.ctx, &data.gl); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); let has_alpha = data @@ -764,7 +764,7 @@ impl WebGLThread { // Check to see if any of the current framebuffer bindings are the surface we're about // to swap out. If so, we'll have to reset them after destroying the surface. let framebuffer_rebinding_info = - FramebufferRebindingInfo::detect(&self.device, &data.ctx, &*data.gl); + FramebufferRebindingInfo::detect(&self.device, &data.ctx, &data.gl); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); debug!("Getting swap chain for {:?}", context_id); @@ -779,7 +779,7 @@ impl WebGLThread { &mut self.device, &mut data.ctx, if data.attributes.preserve_drawing_buffer { - PreserveBuffer::Yes(&*data.gl) + PreserveBuffer::Yes(&data.gl) } else { PreserveBuffer::No }, @@ -795,14 +795,14 @@ impl WebGLThread { .contains(ContextAttributeFlags::ALPHA); let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32]; swap_chain - .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color) + .clear_surface(&mut self.device, &mut data.ctx, &data.gl, clear_color) .unwrap(); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); } // Rebind framebuffers as appropriate. debug!("Rebinding {:?}", context_id); - framebuffer_rebinding_info.apply(&self.device, &data.ctx, &*data.gl); + framebuffer_rebinding_info.apply(&self.device, &data.ctx, &data.gl); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); let SurfaceInfo { @@ -941,7 +941,7 @@ impl WebGLThread { image_buffer_kind: ImageBufferKind, ) -> ImageData { let data = ExternalImageData { - id: ExternalImageId(context_id.0 as u64), + id: ExternalImageId(context_id.0), channel_index: 0, image_type: ExternalImageType::TextureHandle(image_buffer_kind), }; @@ -1288,7 +1288,7 @@ impl WebGLImpl { sender.send(location).unwrap(); }, WebGLCommand::GetUniformLocation(program_id, ref name, ref chan) => { - Self::uniform_location(gl, program_id, &name, chan) + Self::uniform_location(gl, program_id, name, chan) }, WebGLCommand::GetShaderInfoLog(shader_id, ref chan) => { Self::shader_info_log(gl, shader_id, chan) @@ -1297,7 +1297,7 @@ impl WebGLImpl { Self::program_info_log(gl, program_id, chan) }, WebGLCommand::CompileShader(shader_id, ref source) => { - Self::compile_shader(gl, shader_id, &source) + Self::compile_shader(gl, shader_id, source) }, WebGLCommand::CreateBuffer(ref chan) => Self::create_buffer(gl, chan), WebGLCommand::CreateFramebuffer(ref chan) => Self::create_framebuffer(gl, chan), @@ -1426,7 +1426,7 @@ impl WebGLImpl { alpha_treatment, y_axis_treatment, pixel_format, - Cow::Borrowed(&*data), + Cow::Borrowed(data), ); gl.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); @@ -1489,7 +1489,7 @@ impl WebGLImpl { alpha_treatment, y_axis_treatment, pixel_format, - Cow::Borrowed(&*data), + Cow::Borrowed(data), ); gl.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); @@ -1519,7 +1519,7 @@ impl WebGLImpl { size.width as i32, size.height as i32, 0, - &*data, + data, ); }, WebGLCommand::CompressedTexSubImage2D { @@ -1533,13 +1533,13 @@ impl WebGLImpl { } => { gl.compressed_tex_sub_image_2d( target, - level as i32, - xoffset as i32, - yoffset as i32, + level, + xoffset, + yoffset, size.width as i32, size.height as i32, format, - &*data, + data, ); }, WebGLCommand::TexStorage2D(target, levels, internal_format, width, height) => gl @@ -1561,7 +1561,7 @@ impl WebGLImpl { ), WebGLCommand::DrawingBufferWidth(ref sender) => { let size = device - .context_surface_info(&ctx) + .context_surface_info(ctx) .unwrap() .expect("Where's the front buffer?") .size; @@ -1569,7 +1569,7 @@ impl WebGLImpl { }, WebGLCommand::DrawingBufferHeight(ref sender) => { let size = device - .context_surface_info(&ctx) + .context_surface_info(ctx) .unwrap() .expect("Where's the front buffer?") .size; @@ -1615,7 +1615,7 @@ impl WebGLImpl { sender.send(value).unwrap(); }, WebGLCommand::ClientWaitSync(sync_id, flags, timeout, ref sender) => { - let value = gl.client_wait_sync(sync_id.get() as *const _, flags, timeout as u64); + let value = gl.client_wait_sync(sync_id.get() as *const _, flags, timeout); sender.send(value).unwrap(); }, WebGLCommand::WaitSync(sync_id, flags, timeout) => { @@ -1744,10 +1744,10 @@ impl WebGLImpl { } }, WebGLCommand::TexParameteri(target, param, value) => { - gl.tex_parameter_i(target, param as u32, value) + gl.tex_parameter_i(target, param, value) }, WebGLCommand::TexParameterf(target, param, value) => { - gl.tex_parameter_f(target, param as u32, value) + gl.tex_parameter_f(target, param, value) }, WebGLCommand::LinkProgram(program_id, ref sender) => { return sender.send(Self::link_program(gl, program_id)).unwrap(); @@ -2503,7 +2503,7 @@ impl WebGLImpl { /// /// To avoid hard-coding this we would need to use the `sh::GetAttributes` and `sh::GetUniforms` /// API to look up the `x.name` and `x.mappedName` members. -const ANGLE_NAME_PREFIX: &'static str = "_u"; +const ANGLE_NAME_PREFIX: &str = "_u"; fn to_name_in_compiled_shader(s: &str) -> String { map_dot_separated(s, |s, mapped| { @@ -2514,8 +2514,8 @@ fn to_name_in_compiled_shader(s: &str) -> String { fn from_name_in_compiled_shader(s: &str) -> String { map_dot_separated(s, |s, mapped| { - mapped.push_str(if s.starts_with(ANGLE_NAME_PREFIX) { - &s[ANGLE_NAME_PREFIX.len()..] + mapped.push_str(if let Some(stripped) = s.strip_prefix(ANGLE_NAME_PREFIX) { + stripped } else { s }) @@ -2533,6 +2533,7 @@ fn map_dot_separated(s: &str, f: F) -> String { mapped } +#[allow(clippy::too_many_arguments)] fn prepare_pixels( internal_format: TexFormat, data_type: TexDataType, @@ -3057,7 +3058,7 @@ impl WebXRBridge { .map_err(|_| WebXRError::CommunicationError)?; let manager = factory.build(device, contexts)?; let manager_id = unsafe { WebXRLayerManagerId::new(self.next_manager_id) }; - self.next_manager_id = self.next_manager_id + 1; + self.next_manager_id += 1; self.managers.insert(manager_id, manager); Ok(manager_id) } @@ -3100,7 +3101,8 @@ impl WebXRBridge { contexts: &mut dyn WebXRContexts, context_id: WebXRContextId, ) { - for (_, manager) in &mut self.managers { + for manager in self.managers.values_mut() { + #[allow(clippy::unnecessary_to_owned)] // Needs mutable borrow later in destroy for (other_id, layer_id) in manager.layers().to_vec() { if other_id == context_id { manager.destroy_layer(device, contexts, context_id, layer_id); @@ -3315,8 +3317,8 @@ impl<'a> WebXRContexts for WebXRBridgeContexts<'a> { let data = WebGLThread::make_current_if_needed_mut( device, WebGLContextId::from(context_id), - &mut self.contexts, - &mut self.bound_context_id, + self.contexts, + self.bound_context_id, )?; Some(&mut data.ctx) } @@ -3324,8 +3326,8 @@ impl<'a> WebXRContexts for WebXRBridgeContexts<'a> { let data = WebGLThread::make_current_if_needed( device, WebGLContextId::from(context_id), - &self.contexts, - &mut self.bound_context_id, + self.contexts, + self.bound_context_id, )?; Some(&data.gl) } diff --git a/components/compositing/build.rs b/components/compositing/build.rs index 3fe277ca541..828bf622fcb 100644 --- a/components/compositing/build.rs +++ b/components/compositing/build.rs @@ -38,11 +38,11 @@ fn main() { .and_then(|pkg| pkg.get("source").and_then(|source| source.as_str())) .unwrap_or("unknown"); - let parsed: Vec<&str> = source.split("#").collect(); + let parsed: Vec<&str> = source.split('#').collect(); let revision = if parsed.len() > 1 { parsed[1] } else { source }; - let mut revision_module_file = File::create(&revision_file_path).unwrap(); - write!(&mut revision_module_file, "{}", format!("\"{}\"", revision)).unwrap(); + let mut revision_module_file = File::create(revision_file_path).unwrap(); + write!(&mut revision_module_file, "\"{}\"", revision).unwrap(); }, _ => panic!("Cannot find package definitions in lockfile"), } diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 1439f56290a..e9aa0ed80c0 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -42,17 +42,16 @@ use script_traits::{ }; use servo_geometry::{DeviceIndependentPixel, FramebufferUintLength}; use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor}; -use webrender; use webrender::{CaptureBits, RenderApi, Transaction}; use webrender_api::units::{ DeviceIntPoint, DeviceIntSize, DevicePoint, DeviceRect, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D, WorldPoint, }; use webrender_api::{ - self, BuiltDisplayList, ClipId, DirtyRect, DocumentId, Epoch as WebRenderEpoch, + self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch, ExternalScrollId, HitTestFlags, PipelineId as WebRenderPipelineId, PropertyBinding, - ReferenceFrameKind, ScrollClamping, ScrollLocation, SpaceAndClipInfo, SpatialId, - TransformStyle, ZoomFactor, + ReferenceFrameKind, RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo, + SpatialId, SpatialTreeItemKey, TransformStyle, }; use crate::gl::RenderTargetInfo; @@ -80,6 +79,7 @@ const MAX_ZOOM: f32 = 8.0; const MIN_ZOOM: f32 = 0.1; trait ConvertPipelineIdFromWebRender { + #[allow(clippy::wrong_self_convention)] fn from_webrender(&self) -> PipelineId; } @@ -110,13 +110,6 @@ impl FrameTreeId { } } -/// One pixel in layer coordinate space. -/// -/// This unit corresponds to a "pixel" in layer coordinate space, which after scaling and -/// transformation becomes a device pixel. -#[derive(Clone, Copy, Debug)] -enum LayerPixel {} - struct RootPipeline { top_level_browsing_context_id: TopLevelBrowsingContextId, id: Option, @@ -136,9 +129,6 @@ pub struct IOCompositor { /// Tracks details about each active pipeline that the compositor knows about. pipeline_details: HashMap, - /// The scene scale, to allow for zooming and high-resolution painting. - scale: Scale, - /// "Mobile-style" zoom that does not reflow the page. viewport_zoom: PinchZoomFactor, @@ -231,8 +221,6 @@ pub struct IOCompositor { /// Whether to invalidate `prev_offscreen_framebuffer` at the end of the next frame. invalidate_prev_offscreen_framebuffer: bool, - is_running_problem_test: bool, - /// True to exit after page load ('-x'). exit_after_load: bool, @@ -387,7 +375,6 @@ impl IOCompositor { window: Rc, state: InitialCompositorState, composite_target: CompositeTarget, - is_running_problem_test: bool, exit_after_load: bool, convert_mouse_to_touch: bool, top_level_browsing_context_id: TopLevelBrowsingContextId, @@ -409,7 +396,6 @@ impl IOCompositor { port: state.receiver, webviews, pipeline_details: HashMap::new(), - scale: Scale::new(1.0), composition_request: CompositionRequest::NoCompositingNecessary, touch_handler: TouchHandler::new(), pending_scroll_zoom_events: Vec::new(), @@ -437,7 +423,6 @@ impl IOCompositor { next_offscreen_framebuffer: OnceCell::new(), prev_offscreen_framebuffer: None, invalidate_prev_offscreen_framebuffer: false, - is_running_problem_test, exit_after_load, convert_mouse_to_touch, pending_frames: 0, @@ -450,16 +435,14 @@ impl IOCompositor { window: Rc, state: InitialCompositorState, composite_target: CompositeTarget, - is_running_problem_test: bool, exit_after_load: bool, convert_mouse_to_touch: bool, top_level_browsing_context_id: TopLevelBrowsingContextId, ) -> Self { - let mut compositor = IOCompositor::new( + let compositor = IOCompositor::new( window, state, composite_target, - is_running_problem_test, exit_after_load, convert_mouse_to_touch, top_level_browsing_context_id, @@ -467,10 +450,6 @@ impl IOCompositor { // Make sure the GL state is OK compositor.assert_gl_framebuffer_complete(); - - // Set the size of the root layer. - compositor.update_zoom_transform(); - compositor } @@ -541,6 +520,7 @@ impl IOCompositor { /// and the system creates a new native surface that needs to bound to the current /// context. #[allow(unsafe_code)] + #[allow(clippy::not_unsafe_ptr_arg_deref)] // It has an unsafe block inside pub fn replace_native_surface(&mut self, native_widget: *mut c_void, coords: DeviceIntSize) { debug!("Replacing native surface in compositor: {native_widget:?}"); let connection = self.rendering_context.connection(); @@ -648,8 +628,8 @@ impl IOCompositor { self.touch_handler.on_event_processed(result); }, - (CompositorMsg::CreatePng(rect, reply), ShutdownState::NotShuttingDown) => { - let res = self.composite_specific_target(CompositeTarget::SharedMemory, rect); + (CompositorMsg::CreatePng(page_rect, reply), ShutdownState::NotShuttingDown) => { + let res = self.composite_specific_target(CompositeTarget::SharedMemory, page_rect); if let Err(ref e) = res { info!("Error retrieving PNG: {:?}", e); } @@ -666,14 +646,8 @@ impl IOCompositor { ); if is_ready && self.pending_frames == 0 { self.ready_to_save_state = ReadyState::ReadyToSaveImage; - if self.is_running_problem_test { - println!("ready to save image!"); - } } else { self.ready_to_save_state = ReadyState::Unknown; - if self.is_running_problem_test { - println!("resetting ready_to_save_state!"); - } } self.composite_if_necessary(CompositingReason::Headless); }, @@ -697,11 +671,9 @@ impl IOCompositor { ShutdownState::NotShuttingDown, ) => { if recomposite_needed { - if let Some(result) = self.hit_test_at_device_point(self.cursor_pos) { + if let Some(result) = self.hit_test_at_point(self.cursor_pos) { self.update_cursor(result); } - self.composition_request = - CompositionRequest::CompositeNow(CompositingReason::NewWebRenderFrame); } if recomposite_needed || self.animation_callbacks_active() { @@ -728,7 +700,7 @@ impl IOCompositor { CompositorMsg::WebDriverMouseButtonEvent(mouse_event_type, mouse_button, x, y), ShutdownState::NotShuttingDown, ) => { - let dppx = self.device_pixels_per_page_px(); + let dppx = self.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); self.on_mouse_window_event_class(match mouse_event_type { MouseEventType::Click => MouseWindowEvent::Click(mouse_button, point), @@ -738,7 +710,7 @@ impl IOCompositor { }, (CompositorMsg::WebDriverMouseMoveEvent(x, y), ShutdownState::NotShuttingDown) => { - let dppx = self.device_pixels_per_page_px(); + let dppx = self.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); self.on_mouse_window_move_event_class(DevicePoint::new(point.x, point.y)); }, @@ -789,25 +761,46 @@ impl IOCompositor { script_traits::ScriptToCompositorMsg::SendInitialTransaction(pipeline), ) => { let mut txn = Transaction::new(); - txn.set_display_list( - WebRenderEpoch(0), - None, - Default::default(), - (pipeline, Default::default()), - false, - ); - - self.generate_frame(&mut txn); + txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default())); + self.generate_frame(&mut txn, RenderReasons::SCENE); self.webrender_api .send_transaction(self.webrender_document, txn); }, ForwardedToCompositorMsg::Layout( - script_traits::ScriptToCompositorMsg::SendScrollNode(point, scroll_id), + script_traits::ScriptToCompositorMsg::SendScrollNode( + pipeline_id, + point, + external_scroll_id, + ), ) => { + let pipeline_id = PipelineId::from_webrender(pipeline_id); + let pipeline_details = match self.pipeline_details.get_mut(&pipeline_id) { + Some(details) => details, + None => return, + }; + + let offset = LayoutVector2D::new(point.x, point.y); + if !pipeline_details + .scroll_tree + .set_scroll_offsets_for_node_with_external_scroll_id( + external_scroll_id, + -offset, + ) + { + warn!("Could not scroll not with id: {external_scroll_id:?}"); + return; + } + let mut txn = Transaction::new(); - txn.scroll_node_with_id(point, scroll_id, ScrollClamping::NoClamping); - self.generate_frame(&mut txn); + txn.set_scroll_offsets( + external_scroll_id, + vec![SampledScrollOffset { + offset, + generation: 0, + }], + ); + self.generate_frame(&mut txn, RenderReasons::APZ); self.webrender_api .send_transaction(self.webrender_document, txn); }, @@ -819,10 +812,39 @@ impl IOCompositor { display_list_receiver, }, ) => { - let display_list_data = match display_list_receiver.recv() { + // This must match the order from the sender, currently in `shared/script/lib.rs`. + let items_data = match display_list_receiver.recv() { Ok(display_list_data) => display_list_data, - _ => return warn!("Could not recieve WebRender display list."), + Err(error) => { + return warn!( + "Could not receive WebRender display list items data: {error}" + ) + }, }; + let cache_data = match display_list_receiver.recv() { + Ok(display_list_data) => display_list_data, + Err(error) => { + return warn!( + "Could not receive WebRender display list cache data: {error}" + ) + }, + }; + let spatial_tree = match display_list_receiver.recv() { + Ok(display_list_data) => display_list_data, + Err(error) => { + return warn!( + "Could not receive WebRender display list spatial tree: {error}." + ) + }, + }; + let built_display_list = BuiltDisplayList::from_data( + DisplayListPayload { + items_data, + cache_data, + spatial_tree, + }, + display_list_descriptor, + ); let pipeline_id = display_list_info.pipeline_id; let details = self.pipeline_details(PipelineId::from_webrender(pipeline_id)); @@ -830,20 +852,25 @@ impl IOCompositor { details.hit_test_items = display_list_info.hit_test_info; details.install_new_scroll_tree(display_list_info.scroll_tree); - let mut txn = Transaction::new(); - txn.set_display_list( - display_list_info.epoch, - None, - display_list_info.viewport_size, - ( - pipeline_id, - BuiltDisplayList::from_data(display_list_data, display_list_descriptor), - ), - true, - ); - self.generate_frame(&mut txn); + let mut transaction = Transaction::new(); + transaction + .set_display_list(display_list_info.epoch, (pipeline_id, built_display_list)); + + for node in details.scroll_tree.nodes.iter() { + if let (Some(offset), Some(external_id)) = (node.offset(), node.external_id()) { + let offset = LayoutVector2D::new(-offset.x, -offset.y); + transaction.set_scroll_offsets( + external_id, + vec![SampledScrollOffset { + offset, + generation: 0, + }], + ); + } + } + self.generate_frame(&mut transaction, RenderReasons::SCENE); self.webrender_api - .send_transaction(self.webrender_document, txn); + .send_transaction(self.webrender_document, transaction); }, ForwardedToCompositorMsg::Layout(script_traits::ScriptToCompositorMsg::HitTest( @@ -964,9 +991,9 @@ impl IOCompositor { } /// Queue a new frame in the transaction and increase the pending frames count. - fn generate_frame(&mut self, transaction: &mut Transaction) { + fn generate_frame(&mut self, transaction: &mut Transaction, reason: RenderReasons) { self.pending_frames += 1; - transaction.generate_frame(0); + transaction.generate_frame(0, reason); } /// Sets or unsets the animations-running flag for the given pipeline, and schedules a @@ -1003,10 +1030,9 @@ impl IOCompositor { } fn pipeline_details(&mut self, pipeline_id: PipelineId) -> &mut PipelineDetails { - if !self.pipeline_details.contains_key(&pipeline_id) { - self.pipeline_details - .insert(pipeline_id, PipelineDetails::new()); - } + self.pipeline_details + .entry(pipeline_id) + .or_insert_with(PipelineDetails::new); self.pipeline_details .get_mut(&pipeline_id) .expect("Insert then get failed!") @@ -1014,7 +1040,7 @@ impl IOCompositor { pub fn pipeline(&self, pipeline_id: PipelineId) -> Option<&CompositionPipeline> { match self.pipeline_details.get(&pipeline_id) { - Some(ref details) => details.pipeline.as_ref(), + Some(details) => details.pipeline.as_ref(), None => { warn!( "Compositor layer has an unknown pipeline ({:?}).", @@ -1026,20 +1052,20 @@ impl IOCompositor { } /// Set the root pipeline for our WebRender scene to a display list that consists of an iframe - /// for each visible top-level browsing context, applying the pinch zoom transformation if any. + /// for each visible top-level browsing context, applying a transformation on the root for + /// pinch zoom, page zoom, and HiDPI scaling. fn update_root_pipeline(&mut self) { let mut transaction = Transaction::new(); self.update_root_pipeline_in_transaction(&mut transaction); - self.generate_frame(&mut transaction); + self.generate_frame(&mut transaction, RenderReasons::SCENE); self.webrender_api .send_transaction(self.webrender_document, transaction); } /// Set the root pipeline for our WebRender scene to a display list that consists of an iframe - /// for each visible top-level browsing context, applying the pinch zoom transformation if any. + /// for each visible top-level browsing context, applying a transformation on the root for + /// pinch zoom, page zoom, and HiDPI scaling. fn update_root_pipeline_in_transaction(&self, transaction: &mut Transaction) { - let zoom_factor = self.pinch_zoom_level(); - // Every display list needs a pipeline, but we'd like to choose one that is unlikely // to conflict with our content pipelines, which start at (1, 1). (0, 0) is WebRender's // dummy pipeline, so we choose (0, 1). @@ -1047,6 +1073,9 @@ impl IOCompositor { transaction.set_root_pipeline(root_pipeline); let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline); + builder.begin(); + + let zoom_factor = self.device_pixels_per_page_pixel().0; let zoom_reference_frame = builder.push_reference_frame( LayoutPoint::zero(), SpatialId::root_reference_frame(root_pipeline), @@ -1055,21 +1084,26 @@ impl IOCompositor { ReferenceFrameKind::Transform { is_2d_scale_translation: true, should_snap: true, + paired_with_perspective: false, }, + SpatialTreeItemKey::new(0, 0), ); - let dppx = self.page_zoom * self.hidpi_factor(); - let viewport_size = self.embedder_coordinates.get_viewport().size.to_f32() / dppx; - let viewport_size = LayoutSize::from_untyped(viewport_size.to_untyped()); + let scaled_viewport_size = self.embedder_coordinates.get_viewport().size().to_f32() / zoom_factor; + let scaled_viewport_size = LayoutSize::from_untyped(scaled_viewport_size.to_untyped()); + let scaled_viewport_rect = LayoutRect::from_origin_and_size(LayoutPoint::zero(), scaled_viewport_size); + + let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect); + let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]); for (_, webview) in self.webviews.painting_order() { if let Some(pipeline_id) = webview.pipeline_id { - let rect = webview.rect / dppx; + let scaled_webview_rect = webview.rect / zoom_factor; builder.push_iframe( - LayoutRect::from_untyped(&rect.to_untyped()), - LayoutRect::from_untyped(&rect.to_untyped()), + LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), + LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), &SpaceAndClipInfo { spatial_id: zoom_reference_frame, - clip_id: ClipId::root(pipeline_id.to_webrender()), + clip_chain_id, }, pipeline_id.to_webrender(), true, @@ -1077,19 +1111,12 @@ impl IOCompositor { } } - let built_display_list = builder.finalize(); + let built_display_list = builder.end(); // NB: We are always passing 0 as the epoch here, but this doesn't seem to // be an issue. WebRender will still update the scene and generate a new // frame even though the epoch hasn't changed. - let viewport_size = LayoutSize::from_untyped(viewport_size.to_untyped()); - transaction.set_display_list( - WebRenderEpoch(0), - None, - viewport_size, - built_display_list, - false, - ); + transaction.set_display_list(WebRenderEpoch(0), built_display_list); } fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) { @@ -1156,33 +1183,52 @@ impl IOCompositor { self.frame_tree_id.next(); } - pub fn move_resize_webview( + fn move_resize_webview( &mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, rect: DeviceRect, ) { - let dppx = self.page_zoom * self.hidpi_factor(); - if let Some(webview) = self.webviews.get_mut(top_level_browsing_context_id) { - let initial_viewport = rect.size.to_f32() / dppx; - let data = WindowSizeData { - device_pixel_ratio: dppx, - initial_viewport, - }; - if rect.size != webview.rect.size { - let size_type = WindowSizeType::Resize; // FIXME always this value in practice - let msg = - ConstellationMsg::WindowSize(top_level_browsing_context_id, data, size_type); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending window resize to constellation failed ({:?}).", e); - } + let size_changed; + match self.webviews.get_mut(top_level_browsing_context_id) { + Some(webview) => { + size_changed = rect.size() != webview.rect.size(); + webview.rect = rect; } - webview.rect = rect; - self.update_root_pipeline(); - } else { - warn!( - "{}: MoveResizeWebView on unknown top-level browsing context", - top_level_browsing_context_id - ); + None => { + warn!( + "{}: MoveResizeWebView on unknown top-level browsing context", + top_level_browsing_context_id + ); + return; + } + }; + + if size_changed { + self.send_window_size_message_for_top_level_browser_context(rect, top_level_browsing_context_id); + } + + self.update_root_pipeline(); + } + + fn send_window_size_message_for_top_level_browser_context( + &self, + rect: DeviceRect, + top_level_browsing_context_id: TopLevelBrowsingContextId + ) { + // The device pixel ratio used by the style system should include the scale from page pixels + // to device pixels, but not including any pinch zoom. + let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_page_zoom(); + let initial_viewport = rect.size().to_f32() / device_pixel_ratio; + let msg = ConstellationMsg::WindowSize( + top_level_browsing_context_id, + WindowSizeData { + device_pixel_ratio, + initial_viewport, + }, + WindowSizeType::Resize + ); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending window resize to constellation failed ({:?}).", e); } } @@ -1249,27 +1295,14 @@ impl IOCompositor { self.pipeline_details.remove(&pipeline_id); } - fn update_webrender_document_view(&mut self) { - let mut transaction = Transaction::new(); - transaction.set_document_view( - self.embedder_coordinates.get_viewport(), - self.embedder_coordinates.hidpi_factor.get(), - ); - self.webrender_api - .send_transaction(self.webrender_document, transaction); - } - pub fn on_resize_window_event(&mut self) -> bool { - trace!("Compositor resize requested"); + if self.shutdown_state != ShutdownState::NotShuttingDown { + return false; + } let old_coords = self.embedder_coordinates; self.embedder_coordinates = self.window.get_coordinates(); - // A size change could also mean a resolution change. - if self.embedder_coordinates.hidpi_factor != old_coords.hidpi_factor { - self.update_zoom_transform(); - } - // If the framebuffer size has changed, invalidate the current framebuffer object, and mark // the last framebuffer object as needing to be invalidated at the end of the next frame. if self.embedder_coordinates.framebuffer != old_coords.framebuffer { @@ -1277,13 +1310,23 @@ impl IOCompositor { self.invalidate_prev_offscreen_framebuffer = true; } - if self.embedder_coordinates.viewport == old_coords.viewport { + if self.embedder_coordinates.viewport != old_coords.viewport { + let mut transaction = Transaction::new(); + transaction.set_document_view(self.embedder_coordinates.get_viewport()); + self.webrender_api + .send_transaction(self.webrender_document, transaction); + } + + // A size change could also mean a resolution change. + if self.embedder_coordinates.hidpi_factor == old_coords.hidpi_factor && + self.embedder_coordinates.viewport == old_coords.viewport + { return false; } - self.update_webrender_document_view(); + self.update_after_zoom_or_hidpi_change(); self.composite_if_necessary(CompositingReason::Resize); - return true; + true } pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { @@ -1306,7 +1349,7 @@ impl IOCompositor { MouseWindowEvent::MouseUp(_, p) => p, }; - let Some(result) = self.hit_test_at_device_point(point) else { + let Some(result) = self.hit_test_at_point(point) else { // TODO: Notify embedder that the event failed to hit test to any webview. // TODO: Also notify embedder if an event hits a webview but isn’t consumed? return; @@ -1333,14 +1376,7 @@ impl IOCompositor { } } - fn hit_test_at_device_point(&self, point: DevicePoint) -> Option { - let dppx = self.page_zoom * self.hidpi_factor(); - let scaled_point = (point / dppx).to_untyped(); - let world_point = WorldPoint::from_untyped(scaled_point); - return self.hit_test_at_point(world_point); - } - - fn hit_test_at_point(&self, point: WorldPoint) -> Option { + fn hit_test_at_point(&self, point: DevicePoint) -> Option { return self .hit_test_at_point_with_flags_and_pipeline(point, HitTestFlags::empty(), None) .first() @@ -1349,13 +1385,15 @@ impl IOCompositor { fn hit_test_at_point_with_flags_and_pipeline( &self, - point: WorldPoint, + point: DevicePoint, flags: HitTestFlags, pipeline_id: Option, ) -> Vec { + // DevicePoint and WorldPoint are the same for us. + let world_point = WorldPoint::from_untyped(point.to_untyped()); let results = self.webrender_api - .hit_test(self.webrender_document, pipeline_id, point, flags); + .hit_test(self.webrender_document, pipeline_id, world_point, flags); results .items @@ -1398,7 +1436,7 @@ impl IOCompositor { } fn dispatch_mouse_window_move_event_class(&mut self, cursor: DevicePoint) { - let result = match self.hit_test_at_device_point(cursor) { + let result = match self.hit_test_at_point(cursor) { Some(result) => result, None => return, }; @@ -1417,7 +1455,7 @@ impl IOCompositor { identifier: TouchId, point: DevicePoint, ) { - if let Some(result) = self.hit_test_at_device_point(point) { + if let Some(result) = self.hit_test_at_point(point) { let event = TouchEvent( event_type, identifier, @@ -1432,7 +1470,7 @@ impl IOCompositor { } pub fn send_wheel_event(&mut self, delta: WheelDelta, point: DevicePoint) { - if let Some(result) = self.hit_test_at_device_point(point) { + if let Some(result) = self.hit_test_at_point(point) { let event = WheelEvent(delta, result.point_in_viewport, Some(result.node)); let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event); if let Err(e) = self.constellation_chan.send(msg) { @@ -1479,7 +1517,7 @@ impl IOCompositor { scroll_location: ScrollLocation::Delta(LayoutVector2D::from_untyped( scroll_delta.to_untyped(), )), - cursor: cursor, + cursor, event_count: 1, })); }, @@ -1537,7 +1575,7 @@ impl IOCompositor { fn on_scroll_window_event(&mut self, scroll_location: ScrollLocation, cursor: DeviceIntPoint) { self.pending_scroll_zoom_events .push(ScrollZoomEvent::Scroll(ScrollEvent { - scroll_location: scroll_location, + scroll_location, cursor, event_count: 1, })); @@ -1593,11 +1631,10 @@ impl IOCompositor { } let zoom_changed = - self.set_pinch_zoom_level(self.pinch_zoom_level() * combined_magnification); + self.set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification); let scroll_result = combined_scroll_event.and_then(|combined_event| { - let cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped(); - self.scroll_node_at_world_point( - WorldPoint::from_untyped(cursor), + self.scroll_node_at_device_point( + combined_event.cursor.to_f32(), combined_event.scroll_location, ) }); @@ -1611,29 +1648,37 @@ impl IOCompositor { } if let Some((pipeline_id, external_id, offset)) = scroll_result { - let scroll_origin = LayoutPoint::new(-offset.x, -offset.y); - transaction.scroll_node_with_id(scroll_origin, external_id, ScrollClamping::NoClamping); + 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); } - self.generate_frame(&mut transaction); + self.generate_frame(&mut transaction, RenderReasons::APZ); self.webrender_api .send_transaction(self.webrender_document, transaction); } - /// Perform a hit test at the given [`WorldPoint`] and apply the [`ScrollLocation`] + /// Perform a hit test at the given [`DevicePoint`] and apply the [`ScrollLocation`] /// scrolling to the applicable scroll node under that point. If a scroll was /// performed, returns the [`PipelineId`] of the node scrolled, the id, and the final /// scroll delta. - fn scroll_node_at_world_point( + fn scroll_node_at_device_point( &mut self, - cursor: WorldPoint, + cursor: DevicePoint, scroll_location: ScrollLocation, ) -> Option<(PipelineId, ExternalScrollId, LayoutVector2D)> { let scroll_location = match scroll_location { ScrollLocation::Delta(delta) => { - let scaled_delta = - (Vector2D::from_untyped(delta.to_untyped()) / self.scale).to_untyped(); + let device_pixels_per_page = self.device_pixels_per_page_pixel(); + let scaled_delta = (Vector2D::from_untyped(delta.to_untyped()) / + device_pixels_per_page) + .to_untyped(); let calculated_delta = LayoutVector2D::from_untyped(scaled_delta); ScrollLocation::Delta(calculated_delta) }, @@ -1718,20 +1763,19 @@ impl IOCompositor { self.embedder_coordinates.hidpi_factor } - fn device_pixels_per_page_px(&self) -> Scale { - self.page_zoom * self.hidpi_factor() + fn device_pixels_per_page_pixel(&self) -> Scale { + self.device_pixels_per_page_pixel_not_including_page_zoom() * self.pinch_zoom_level() } - fn update_zoom_transform(&mut self) { - let scale = self.device_pixels_per_page_px(); - self.scale = Scale::new(scale.get()); + fn device_pixels_per_page_pixel_not_including_page_zoom( + &self, + ) -> Scale { + self.page_zoom * self.hidpi_factor() } pub fn on_zoom_reset_window_event(&mut self) { self.page_zoom = Scale::new(1.0); - self.update_zoom_transform(); - self.update_webrender_document_view(); - self.update_page_zoom_for_webrender(); + self.update_after_zoom_or_hidpi_change(); } pub fn on_zoom_window_event(&mut self, magnification: f32) { @@ -1740,18 +1784,16 @@ impl IOCompositor { .max(MIN_ZOOM) .min(MAX_ZOOM), ); - self.update_zoom_transform(); - self.update_webrender_document_view(); - self.update_page_zoom_for_webrender(); + self.update_after_zoom_or_hidpi_change(); } - fn update_page_zoom_for_webrender(&mut self) { - let page_zoom = ZoomFactor::new(self.page_zoom.get()); + fn update_after_zoom_or_hidpi_change(&mut self) { + for (top_level_browsing_context_id, webview) in self.webviews.painting_order() { + self.send_window_size_message_for_top_level_browser_context(webview.rect, *top_level_browsing_context_id); + } - let mut txn = webrender::Transaction::new(); - txn.set_page_zoom(page_zoom); - self.webrender_api - .send_transaction(self.webrender_document, txn); + // Update the root transform in WebRender to reflect the new zoom. + self.update_root_pipeline(); } /// Simulate a pinch zoom @@ -1762,21 +1804,18 @@ impl IOCompositor { } fn send_scroll_positions_to_layout_for_pipeline(&self, pipeline_id: &PipelineId) { - let details = match self.pipeline_details.get(&pipeline_id) { + let details = match self.pipeline_details.get(pipeline_id) { Some(details) => details, None => return, }; let mut scroll_states = Vec::new(); details.scroll_tree.nodes.iter().for_each(|node| { - match (node.external_id(), node.offset()) { - (Some(scroll_id), Some(scroll_offset)) => { - scroll_states.push(ScrollState { - scroll_id, - scroll_offset, - }); - }, - _ => {}, + if let (Some(scroll_id), Some(scroll_offset)) = (node.external_id(), node.offset()) { + scroll_states.push(ScrollState { + scroll_id, + scroll_offset, + }); } }); @@ -1791,7 +1830,7 @@ impl IOCompositor { // Check if any pipelines currently have active animations or animation callbacks. fn animations_active(&self) -> bool { - for (_, details) in &self.pipeline_details { + for details in self.pipeline_details.values() { // If animations are currently running, then don't bother checking // with the constellation if the output image is stable. if details.animations_running { @@ -1825,7 +1864,7 @@ impl IOCompositor { // This gets sent to the constellation for comparison with the current // frame tree. let mut pipeline_epochs = HashMap::new(); - for (id, _) in &self.pipeline_details { + for id in self.pipeline_details.keys() { let webrender_pipeline_id = id.to_webrender(); if let Some(WebRenderEpoch(epoch)) = self .webrender @@ -1856,9 +1895,6 @@ impl IOCompositor { // for saving. // Reset the flag so that we check again in the future // TODO: only reset this if we load a new document? - if self.is_running_problem_test { - println!("was ready to save, resetting ready_to_save_state"); - } self.ready_to_save_state = ReadyState::Unknown; Ok(()) }, @@ -1875,14 +1911,8 @@ impl IOCompositor { self.start_shutting_down(); } }, - Err(e) => { - if self.is_running_problem_test { - if e != UnableToComposite::NotReadyToPaintImage( - NotReadyToPaint::WaitingOnConstellation, - ) { - println!("not ready to composite: {:?}", e); - } - } + Err(error) => { + trace!("Unable to composite: {error:?}"); }, } } @@ -1894,7 +1924,7 @@ impl IOCompositor { fn composite_specific_target( &mut self, target: CompositeTarget, - rect: Option>, + page_rect: Option>, ) -> Result, UnableToComposite> { if self.waiting_on_present { debug!("tried to composite while waiting on present"); @@ -2002,7 +2032,7 @@ impl IOCompositor { continue; } // in which case, we remove it from the list of pending metrics, - to_remove.push(id.clone()); + to_remove.push(*id); if let Some(pipeline) = self.pipeline(*id) { // and inform layout with the measured paint time. let message = LayoutControlMsg::PaintMetric(epoch, paint_time); @@ -2019,8 +2049,8 @@ impl IOCompositor { } } - let (x, y, width, height) = if let Some(rect) = rect { - let rect = self.device_pixels_per_page_px().transform_rect(&rect); + let (x, y, width, height) = if let Some(rect) = page_rect { + let rect = self.device_pixels_per_page_pixel().transform_rect(&rect); let x = rect.origin.x as i32; // We need to convert to the bottom-left origin coordinate @@ -2069,7 +2099,7 @@ impl IOCompositor { width: img.width(), height: img.height(), format: PixelFormat::RGB8, - bytes: ipc::IpcSharedMemory::from_bytes(&*img), + bytes: ipc::IpcSharedMemory::from_bytes(&img), id: None, cors_status: CorsStatus::Safe, }) @@ -2135,17 +2165,11 @@ impl IOCompositor { } fn composite_if_necessary(&mut self, reason: CompositingReason) { - if self.composition_request == CompositionRequest::NoCompositingNecessary { - if self.is_running_problem_test { - println!("updating composition_request ({:?})", reason); - } - self.composition_request = CompositionRequest::CompositeNow(reason) - } else if self.is_running_problem_test { - println!( - "composition_request is already {:?}", - self.composition_request - ); - } + trace!( + "Will schedule a composite {reason:?}. Previously was {:?}", + self.composition_request + ); + self.composition_request = CompositionRequest::CompositeNow(reason) } fn clear_background(&self) { @@ -2165,10 +2189,10 @@ impl IOCompositor { for (_, webview) in self.webviews.painting_order() { let rect = self.embedder_coordinates.flip_rect(&webview.rect.to_i32()); gl.scissor( - rect.origin.x, - rect.origin.y, - rect.size.width, - rect.size.height, + rect.min.x, + rect.min.y, + rect.size().width, + rect.size().height, ); gl.enable(gleam::gl::SCISSOR_TEST); gl.clear(gleam::gl::COLOR_BUFFER_BIT); @@ -2259,10 +2283,7 @@ impl IOCompositor { pub fn repaint_synchronously(&mut self) { while self.shutdown_state != ShutdownState::ShuttingDown { let msg = self.port.recv_compositor_msg(); - let need_recomposite = match msg { - CompositorMsg::NewWebRenderFrameReady(_) => true, - _ => false, - }; + let need_recomposite = matches!(msg, CompositorMsg::NewWebRenderFrameReady(_)); let keep_going = self.handle_browser_message(msg); if need_recomposite { self.composite(); @@ -2274,8 +2295,8 @@ impl IOCompositor { } } - pub fn pinch_zoom_level(&self) -> f32 { - self.viewport_zoom.get() + pub fn pinch_zoom_level(&self) -> Scale { + Scale::new(self.viewport_zoom.get()) } fn set_pinch_zoom_level(&mut self, mut zoom: f32) -> bool { @@ -2305,7 +2326,7 @@ impl IOCompositor { self.webrender.set_debug_flags(flags); let mut txn = Transaction::new(); - self.generate_frame(&mut txn); + self.generate_frame(&mut txn, RenderReasons::TESTING); self.webrender_api .send_transaction(self.webrender_document, txn); } @@ -2323,7 +2344,7 @@ impl IOCompositor { .map(|dir| dir.join("capture_webrender").join(&capture_id)) .ok() }) - .find(|val| match create_dir_all(&val) { + .find(|val| match create_dir_all(val) { Ok(_) => true, Err(err) => { eprintln!("Unable to create path '{:?}' for capture: {:?}", &val, err); diff --git a/components/compositing/gl.rs b/components/compositing/gl.rs index 407fb34546b..18761c5829e 100644 --- a/components/compositing/gl.rs +++ b/components/compositing/gl.rs @@ -132,7 +132,7 @@ impl RenderTargetInfo { let dst_start = y * stride; let src_start = (height - y - 1) * stride; let src_slice = &orig_pixels[src_start..src_start + stride]; - (&mut pixels[dst_start..dst_start + stride]).clone_from_slice(&src_slice[..stride]); + pixels[dst_start..dst_start + stride].clone_from_slice(&src_slice[..stride]); } RgbImage::from_raw(width as u32, height as u32, pixels).expect("Flipping image failed!") diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index 34bb90099e4..0acd0690b43 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -25,10 +25,7 @@ pub struct TouchPoint { impl TouchPoint { pub fn new(id: TouchId, point: Point2D) -> Self { - TouchPoint { - id: id, - point: point, - } + TouchPoint { id, point } } } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 9563c9f1e40..b55b8ad0a2e 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -234,9 +234,8 @@ impl EmbedderCoordinates { /// Flip the given rect. /// This should be used when drawing directly to the framebuffer with OpenGL commands. pub fn flip_rect(&self, rect: &DeviceIntRect) -> DeviceIntRect { - let fb_height = self.framebuffer.height; let mut result = rect.clone(); - result.origin.y = fb_height - result.origin.y - result.size.height; + result.min.y = self.framebuffer.height - result.min.y - result.size().height; result } diff --git a/components/config/basedir.rs b/components/config/basedir.rs index fbae2a7edca..fd17e482b88 100644 --- a/components/config/basedir.rs +++ b/components/config/basedir.rs @@ -35,7 +35,7 @@ pub fn default_config_dir() -> Option { Some(config_dir) } -#[cfg(all(target_os = "windows"))] +#[cfg(target_os = "windows")] pub fn default_config_dir() -> Option { let mut config_dir = ::dirs_next::config_dir().unwrap(); config_dir.push("Servo"); diff --git a/components/config/opts.rs b/components/config/opts.rs index 5cf394bb297..0f909148859 100644 --- a/components/config/opts.rs +++ b/components/config/opts.rs @@ -7,7 +7,7 @@ use std::default::Default; use std::fs::{self, File}; -use std::io::{self, Read, Write}; +use std::io::Read; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{RwLock, RwLockReadGuard}; @@ -27,8 +27,6 @@ use crate::{pref, set_pref}; /// Global flags for Servo, currently set on the command line. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Opts { - pub is_running_problem_test: bool, - /// Whether or not the legacy layout system is enabled. pub legacy_layout: bool, @@ -385,7 +383,7 @@ pub enum OutputOptions { } fn args_fail(msg: &str) -> ! { - writeln!(io::stderr(), "{}", msg).unwrap(); + eprintln!("{}", msg); process::exit(1) } @@ -398,7 +396,6 @@ pub fn multiprocess() -> bool { pub fn default_opts() -> Opts { Opts { - is_running_problem_test: false, legacy_layout: false, tile_size: 512, time_profiling: None, @@ -598,18 +595,6 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR DebugOptions::print_usage(app_name) } - let cwd = env::current_dir().unwrap(); - let url_opt = if !opt_match.free.is_empty() { - Some(&opt_match.free[0][..]) - } else { - None - }; - let is_running_problem_test = url_opt.as_ref().map_or(false, |url| { - url.starts_with("http://web-platform.test:8000/2dcontext/drawing-images-to-the-canvas/") || - url.starts_with("http://web-platform.test:8000/_mozilla/mozilla/canvas/") || - url.starts_with("http://web-platform.test:8000/_mozilla/css/canvas_over_area.html") - }); - let tile_size: usize = match opt_match.opt_str("s") { Some(tile_size_str) => tile_size_str .parse() @@ -733,6 +718,7 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR .opt_strs("user-stylesheet") .iter() .map(|filename| { + let cwd = env::current_dir().unwrap(); let path = cwd.join(filename); let url = ServoUrl::from_url(Url::from_file_path(&path).unwrap()); let mut contents = Vec::new(); @@ -754,7 +740,6 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR let opts = Opts { debug: debug_options.clone(), - is_running_problem_test, legacy_layout, tile_size, time_profiling, @@ -793,7 +778,7 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR set_pref!(layout.threads, layout_threads as i64); } - return ArgumentParsingResult::ChromeProcess(opt_match); + ArgumentParsingResult::ChromeProcess(opt_match) } pub enum ArgumentParsingResult { diff --git a/components/config/pref_util.rs b/components/config/pref_util.rs index 11e2f7f94a8..d8cfa78aaea 100644 --- a/components/config/pref_util.rs +++ b/components/config/pref_util.rs @@ -55,10 +55,7 @@ impl PrefValue { } pub fn is_missing(&self) -> bool { - match self { - PrefValue::Missing => true, - _ => false, - } + matches!(self, PrefValue::Missing) } pub fn from_json_value(value: &Value) -> Option { @@ -164,7 +161,7 @@ impl From for [f64; 4] { let mut f = values.into_iter().map(|v| v.try_into()); if f.all(|v| v.is_ok()) { let f = f.flatten().collect::>(); - return [f[0], f[1], f[2], f[3]]; + [f[0], f[1], f[2], f[3]] } else { panic!( "Cannot convert PrefValue to {:?}", @@ -191,7 +188,7 @@ pub enum PrefError { impl fmt::Display for PrefError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - PrefError::NoSuchPref(s) | PrefError::InvalidValue(s) => f.write_str(&s), + PrefError::NoSuchPref(s) | PrefError::InvalidValue(s) => f.write_str(s), PrefError::JsonParseErr(e) => e.fmt(f), } } @@ -201,6 +198,7 @@ impl std::error::Error for PrefError {} pub struct Accessor { pub getter: Box V + Sync>, + #[allow(clippy::type_complexity)] pub setter: Box, } @@ -261,7 +259,7 @@ impl<'m, P: Clone> Preferences<'m, P> { } /// Creates an iterator over all keys and values - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter(&self) -> impl Iterator + '_ { let prefs = self.user_prefs.read().unwrap(); self.accessors .iter() @@ -269,16 +267,17 @@ impl<'m, P: Clone> Preferences<'m, P> { } /// Creates an iterator over all keys - pub fn keys<'a>(&'a self) -> impl Iterator + 'a { + pub fn keys(&self) -> impl Iterator { self.accessors.keys().map(String::as_str) } - fn set_inner(&self, key: &str, mut prefs: &mut P, val: V) -> Result<(), PrefError> + fn set_inner(&self, key: &str, prefs: &mut P, val: V) -> Result<(), PrefError> where V: Into, { if let Some(accessor) = self.accessors.get(key) { - Ok((accessor.setter)(&mut prefs, val.into())) + (accessor.setter)(prefs, val.into()); + Ok(()) } else { Err(PrefError::NoSuchPref(String::from(key))) } diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 826605da6d9..f9c7c39bf82 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -67,7 +67,7 @@ pub fn add_user_prefs(prefs: HashMap) { for (key, value) in prefs.iter() { set_stylo_pref_ref(key, value); } - if let Err(error) = PREFS.set_all(prefs.into_iter()) { + if let Err(error) = PREFS.set_all(prefs) { panic!("Error setting preference: {:?}", error); } } @@ -106,15 +106,15 @@ impl TryFrom<&PrefValue> for StyloPrefValue { type Error = TryFromPrefValueError; fn try_from(value: &PrefValue) -> Result { - match value { - &PrefValue::Int(value) => { + match *value { + PrefValue::Int(value) => { if let Ok(value) = value.try_into() { Ok(Self::Int(value)) } else { Err(TryFromPrefValueError::IntegerOverflow(value)) } }, - &PrefValue::Bool(value) => Ok(Self::Bool(value)), + PrefValue::Bool(value) => Ok(Self::Bool(value)), _ => Err(TryFromPrefValueError::UnmappedType), } } @@ -122,7 +122,7 @@ impl TryFrom<&PrefValue> for StyloPrefValue { pub fn read_prefs_map(txt: &str) -> Result, PrefError> { let prefs: HashMap = - serde_json::from_str(txt).map_err(|e| PrefError::JsonParseErr(e))?; + serde_json::from_str(txt).map_err(PrefError::JsonParseErr)?; prefs .into_iter() .map(|(k, pref_value)| { @@ -133,7 +133,7 @@ pub fn read_prefs_map(txt: &str) -> Result, PrefError Value::Number(n) if n.is_f64() => PrefValue::Float(n.as_f64().unwrap()), Value::String(s) => PrefValue::Str(s.to_owned()), Value::Array(v) => { - let mut array = v.iter().map(|v| PrefValue::from_json_value(v)); + let mut array = v.iter().map(PrefValue::from_json_value); if array.all(|v| v.is_some()) { PrefValue::Array(array.flatten().collect()) } else { diff --git a/components/config_plugins/parse.rs b/components/config_plugins/parse.rs index 3a390f2f07f..63a3d66dfda 100644 --- a/components/config_plugins/parse.rs +++ b/components/config_plugins/parse.rs @@ -132,7 +132,7 @@ impl Parse for RootTypeDef { impl Parse for NewTypeDef { fn parse(input: ParseStream<'_>) -> Result { let content; - #[allow(clippy::eval_order_dependence)] + #[allow(clippy::mixed_read_write_in_expression)] Ok(NewTypeDef { _braces: braced!(content in input), fields: Punctuated::parse_terminated_with(&content, Field::parse)?, diff --git a/components/constellation/browsingcontext.rs b/components/constellation/browsingcontext.rs index c7f43e0d977..d7bfaab3d74 100644 --- a/components/constellation/browsingcontext.rs +++ b/components/constellation/browsingcontext.rs @@ -2,6 +2,8 @@ * 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/. */ +#![allow(clippy::too_many_arguments)] + use std::collections::{HashMap, HashSet}; use euclid::Size2D; @@ -198,7 +200,7 @@ impl<'a> Iterator for AllBrowsingContextsIterator<'a> { let child_browsing_context_ids = browsing_context .pipelines .iter() - .filter_map(|pipeline_id| pipelines.get(&pipeline_id)) + .filter_map(|pipeline_id| pipelines.get(pipeline_id)) .flat_map(|pipeline| pipeline.children.iter()); self.stack.extend(child_browsing_context_ids); return Some(browsing_context); diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index d8153c5272e..ee4eee5a50d 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -84,6 +84,8 @@ //! //! See +#![allow(clippy::too_many_arguments)] + use std::borrow::{Cow, ToOwned}; use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet, VecDeque}; @@ -475,8 +477,6 @@ pub struct Constellation { /// currently being pressed. pressed_mouse_buttons: u16, - is_running_problem_test: bool, - /// If True, exits on thread failure instead of displaying about:failure hard_fail: bool, @@ -621,7 +621,6 @@ where initial_window_size: WindowSizeData, random_pipeline_closure_probability: Option, random_pipeline_closure_seed: Option, - is_running_problem_test: bool, hard_fail: bool, enable_canvas_antialiasing: bool, canvas_create_sender: Sender, @@ -711,7 +710,7 @@ where ROUTER.add_route( webrender_ipc_receiver.to_opaque(), Box::new(move |message| { - let _ = compositor_proxy.send(CompositorMsg::Forwarded( + compositor_proxy.send(CompositorMsg::Forwarded( ForwardedToCompositorMsg::Layout( message.to().expect("conversion failure"), ), @@ -723,7 +722,7 @@ where ROUTER.add_route( webrender_image_ipc_receiver.to_opaque(), Box::new(move |message| { - let _ = compositor_proxy.send(CompositorMsg::Forwarded( + compositor_proxy.send(CompositorMsg::Forwarded( ForwardedToCompositorMsg::Net( message.to().expect("conversion failure"), ), @@ -746,12 +745,12 @@ where background_monitor_register, background_monitor_control_senders: background_hang_monitor_control_ipc_senders, layout_sender: layout_ipc_sender, - script_receiver: script_receiver, - compositor_receiver: compositor_receiver, + script_receiver, + compositor_receiver, layout_factory, - layout_receiver: layout_receiver, - network_listener_sender: network_listener_sender, - network_listener_receiver: network_listener_receiver, + layout_receiver, + network_listener_sender, + network_listener_receiver, embedder_proxy: state.embedder_proxy, compositor_proxy: state.compositor_proxy, webviews: WebViewManager::default(), @@ -761,7 +760,7 @@ where private_resource_threads: state.private_resource_threads, font_cache_thread: state.font_cache_thread, sw_managers: Default::default(), - swmanager_receiver: swmanager_receiver, + swmanager_receiver, swmanager_ipc_sender, browsing_context_group_set: Default::default(), browsing_context_group_next_id: Default::default(), @@ -807,7 +806,6 @@ where canvas_ipc_sender, pending_approval_navigations: HashMap::new(), pressed_mouse_buttons: 0, - is_running_problem_test, hard_fail, enable_canvas_antialiasing, glplayer_threads: state.glplayer_threads, @@ -858,7 +856,7 @@ where Some(browsing_context_id) => { let opener = self .browsing_contexts - .get(&browsing_context_id) + .get(browsing_context_id) .ok_or("Opener was closed before the openee started")?; self.browsing_context_group_set .get(&opener.bc_group_id) @@ -870,7 +868,7 @@ where .filter_map(|(_, bc_group)| { if bc_group .top_level_browsing_context_set - .contains(&top_level_browsing_context_id) + .contains(top_level_browsing_context_id) { Some(bc_group) } else { @@ -915,7 +913,7 @@ where .top_level_browsing_context_set .contains(&top_level_browsing_context_id) { - Some(id.clone()) + Some(*id) } else { None } @@ -929,10 +927,10 @@ where }, }; if let Some(bc_group) = self.browsing_context_group_set.get_mut(&bc_group_id) { - if !bc_group + if bc_group .event_loops .insert(host.clone(), event_loop) - .is_none() + .is_some() { warn!( "Double-setting an event-loop for {:?} at {:?}", @@ -1028,7 +1026,7 @@ where opener, script_to_constellation_chan: ScriptToConstellationChan { sender: self.script_sender.clone(), - pipeline_id: pipeline_id, + pipeline_id, }, namespace_request_sender: self.namespace_ipc_sender.clone(), pipeline_namespace_id: self.next_pipeline_namespace_id(), @@ -1155,7 +1153,7 @@ where }) .last() { - Some(id) => id.clone(), + Some(id) => *id, None => { warn!("Top-level was unexpectedly removed from its top_level_browsing_context_set"); return; @@ -1213,7 +1211,7 @@ where let scheduler_timeout = self .timer_scheduler .check_timers() - .map(|timeout| after(timeout)) + .map(after) .unwrap_or(never()); // Get one incoming request. @@ -1336,7 +1334,7 @@ where } fn handle_request_from_compositor(&mut self, message: FromCompositorMsg) { - trace!("Got compositor message: {:?}", message); + trace_msg_from_compositor!(message, "{message:?}"); match message { FromCompositorMsg::Exit => { self.handle_exit(); @@ -1405,12 +1403,12 @@ where } }, None => { - return warn!( + warn!( "{}: AllowNavigationResponse for unknown request", pipeline_id - ); + ) }, - }; + } }, FromCompositorMsg::ClearCache => { self.public_resource_threads.clear_cache(); @@ -1450,15 +1448,10 @@ where FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => { let is_ready = self.handle_is_ready_to_save_image(pipeline_states); debug!("Ready to save image {:?}.", is_ready); - if self.is_running_problem_test { - println!("got ready to save image query, result is {:?}", is_ready); - } - let is_ready = is_ready == ReadyToSave::Ready; self.compositor_proxy - .send(CompositorMsg::IsReadyToSaveImageReply(is_ready)); - if self.is_running_problem_test { - println!("sent response"); - } + .send(CompositorMsg::IsReadyToSaveImageReply( + is_ready == ReadyToSave::Ready, + )); }, // Create a new top level browsing context. Will use response_chan to return // the browsing context id. @@ -1632,11 +1625,7 @@ where fn handle_request_from_script(&mut self, message: (PipelineId, FromScriptMsg)) { let (source_pipeline_id, content) = message; - trace!( - "{}: Message from pipeline: {:?}", - source_pipeline_id, - content, - ); + trace_script_msg!(content, "{source_pipeline_id}: {content:?}"); let source_top_ctx_id = match self .pipelines @@ -1853,7 +1842,7 @@ where let result = self .browsing_contexts .get(&browsing_context_id) - .and_then(|bc| Some(bc.top_level_id)); + .map(|bc| bc.top_level_id); if let Err(e) = response_sender.send(result) { warn!( "Sending reply to get top for browsing context info failed ({:?}).", @@ -1871,7 +1860,7 @@ where .get(&browsing_context_id) .and_then(|bc| self.pipelines.get(&bc.pipeline_id)) .and_then(|pipeline| pipeline.children.get(index)) - .map(|maybe_bcid| *maybe_bcid); + .copied(); if let Err(e) = response_sender.send(result) { warn!( "Sending reply to get child browsing context ID failed ({:?}).", @@ -1907,15 +1896,13 @@ where // the active media session. // Events coming from inactive media sessions are discarded. if self.active_media_session.is_some() { - match event { - MediaSessionEvent::PlaybackStateChange(ref state) => { - match state { - MediaSessionPlaybackState::Playing | - MediaSessionPlaybackState::Paused => (), - _ => return, - }; - }, - _ => (), + if let MediaSessionEvent::PlaybackStateChange(ref state) = event { + if !matches!( + state, + MediaSessionPlaybackState::Playing | MediaSessionPlaybackState::Paused + ) { + return; + } }; } self.active_media_session = Some(pipeline_id); @@ -1951,7 +1938,7 @@ where pipeline_id: &PipelineId, origin: &ImmutableOrigin, ) -> Result<(), ()> { - let pipeline_origin = match self.pipelines.get(&pipeline_id) { + let pipeline_origin = match self.pipelines.get(pipeline_id) { Some(pipeline) => pipeline.load_data.url.origin(), None => { warn!("Received message from closed or unknown pipeline."); @@ -1991,7 +1978,7 @@ where continue; } - if let Some(broadcast_ipc_sender) = self.broadcast_routers.get(&router) { + if let Some(broadcast_ipc_sender) = self.broadcast_routers.get(router) { if broadcast_ipc_sender.send(message.clone()).is_err() { warn!("Failed to broadcast message to router: {:?}", router); } @@ -2056,12 +2043,9 @@ where { return warn!("Attempt to add channel name from an unexpected origin."); } - let channels = self - .broadcast_channels - .entry(origin) - .or_insert_with(HashMap::new); + let channels = self.broadcast_channels.entry(origin).or_default(); - let routers = channels.entry(channel_name).or_insert_with(Vec::new); + let routers = channels.entry(channel_name).or_default(); routers.push(router_id); } @@ -2127,7 +2111,7 @@ where }; let browsing_context_group = if let Some(bcg) = self .browsing_context_group_set - .get_mut(&browsing_context_group_id) + .get_mut(browsing_context_group_id) { bcg } else { @@ -2156,7 +2140,7 @@ where FromScriptMsg::RequestAdapter(response_sender, options, ids) => match webgpu_chan { None => { if let Err(e) = response_sender.send(None) { - return warn!("Failed to send request adapter message: {}", e); + warn!("Failed to send request adapter message: {}", e) } }, Some(webgpu_chan) => { @@ -2172,18 +2156,18 @@ where }, FromScriptMsg::GetWebGPUChan(response_sender) => { if response_sender.send(webgpu_chan).is_err() { - return warn!( + warn!( "{}: Failed to send WebGPU channel to pipeline", source_pipeline_id - ); + ) } }, - _ => return warn!("Wrong message type in handle_wgpu_request"), + _ => warn!("Wrong message type in handle_wgpu_request"), } } fn handle_request_from_layout(&mut self, message: FromLayoutMsg) { - debug!("Got layout message: {:?}", message); + trace_layout_msg!(message, "{message:?}"); match message { // Layout sends new sizes for all subframes. This needs to be reflected by all // frame trees in the navigation context containing the subframe. @@ -2429,7 +2413,7 @@ where // In both the managed and completion of a transfer case, we forward the message. // Note that in both cases, if the port is transferred before the message is handled, // it will be sent back here and buffered while the transfer is ongoing. - if let Some(ipc_sender) = self.message_port_routers.get(&router_id) { + if let Some(ipc_sender) = self.message_port_routers.get(router_id) { let _ = ipc_sender.send(MessagePortMsg::NewTask(port_id, task)); } else { warn!("No message-port sender for {:?}", router_id); @@ -2776,7 +2760,7 @@ where let receivers = self .browsing_context_group_set .values() - .map(|browsing_context_group| { + .flat_map(|browsing_context_group| { browsing_context_group.webgpus.values().map(|webgpu| { let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); if let Err(e) = webgpu.exit(sender) { @@ -2787,8 +2771,7 @@ where } }) }) - .flatten() - .filter_map(|r| r); + .flatten(); for receiver in receivers { if let Err(e) = receiver.recv() { @@ -3060,7 +3043,7 @@ where let new_bc_group_id = self.next_browsing_context_group_id(); new_bc_group .top_level_browsing_context_set - .insert(top_level_browsing_context_id.clone()); + .insert(top_level_browsing_context_id); self.browsing_context_group_set .insert(new_bc_group_id, new_bc_group); @@ -3309,10 +3292,10 @@ where browsing_context_is_visible, ); self.add_pending_change(SessionHistoryChange { - top_level_browsing_context_id: top_level_browsing_context_id, - browsing_context_id: browsing_context_id, - new_pipeline_id: new_pipeline_id, - replace: replace, + top_level_browsing_context_id, + browsing_context_id, + new_pipeline_id, + replace, // Browsing context for iframe already exists. new_browsing_context_info: None, window_size: load_info.window_size.initial_viewport, @@ -3446,7 +3429,7 @@ where }; bc_group .top_level_browsing_context_set - .insert(new_top_level_browsing_context_id.clone()); + .insert(new_top_level_browsing_context_id); self.add_pending_change(SessionHistoryChange { top_level_browsing_context_id: new_top_level_browsing_context_id, @@ -3647,9 +3630,9 @@ where is_visible, ); self.add_pending_change(SessionHistoryChange { - top_level_browsing_context_id: top_level_browsing_context_id, - browsing_context_id: browsing_context_id, - new_pipeline_id: new_pipeline_id, + top_level_browsing_context_id, + browsing_context_id, + new_pipeline_id, replace, // `load_url` is always invoked on an existing browsing context. new_browsing_context_info: None, @@ -3743,7 +3726,7 @@ where match replacement_enabled { HistoryEntryReplacement::Disabled => { - let diff = SessionHistoryDiff::HashDiff { + let diff = SessionHistoryDiff::Hash { pipeline_reloader: NeedsToReload::No(pipeline_id), new_url, old_url, @@ -3780,7 +3763,7 @@ where .rev() { match diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, ref new_reloader, .. @@ -3788,7 +3771,7 @@ where browsing_context_changes .insert(browsing_context_id, new_reloader.clone()); }, - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { ref pipeline_reloader, new_history_state_id, ref new_url, @@ -3804,7 +3787,7 @@ where url_to_load.insert(pipeline_id, new_url.clone()); }, }, - SessionHistoryDiff::HashDiff { + SessionHistoryDiff::Hash { ref pipeline_reloader, ref new_url, .. @@ -3832,7 +3815,7 @@ where for diff in session_history.past.drain(past_length - back..).rev() { match diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, ref old_reloader, .. @@ -3840,7 +3823,7 @@ where browsing_context_changes .insert(browsing_context_id, old_reloader.clone()); }, - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { ref pipeline_reloader, old_history_state_id, ref old_url, @@ -3856,7 +3839,7 @@ where url_to_load.insert(pipeline_id, old_url.clone()); }, }, - SessionHistoryDiff::HashDiff { + SessionHistoryDiff::Hash { ref pipeline_reloader, ref old_url, .. @@ -4087,7 +4070,7 @@ where }, }; - let diff = SessionHistoryDiff::PipelineDiff { + let diff = SessionHistoryDiff::Pipeline { pipeline_reloader: NeedsToReload::No(pipeline_id), new_history_state_id: history_state_id, new_url: url, @@ -4522,7 +4505,7 @@ where CompositorEvent::KeyboardEvent(event), ); if let Err(e) = event_loop.send(control_msg) { - return self.handle_send_error(pipeline_id, e); + self.handle_send_error(pipeline_id, e) } }, WebDriverCommandMsg::MouseButtonAction(mouse_event_type, mouse_button, x, y) => { @@ -4558,9 +4541,9 @@ where }, }; match self.pipelines.get(&pipeline_id) { - None => return warn!("{pipeline_id}: Tried to notify visibility after closure"), + None => warn!("{pipeline_id}: Tried to notify visibility after closure"), Some(pipeline) => pipeline.notify_visibility(visible), - }; + } } fn notify_history_changed(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) { @@ -4601,7 +4584,7 @@ where // is the LoadData of the parent browsing context. let resolve_load_data_future = |previous_load_data: &mut LoadData, diff: &SessionHistoryDiff| match *diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, ref new_reloader, .. @@ -4627,7 +4610,7 @@ where let resolve_load_data_past = |previous_load_data: &mut LoadData, diff: &SessionHistoryDiff| match *diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, ref old_reloader, .. @@ -4781,7 +4764,7 @@ where NeedsToReload::Yes(..) => (None, None), } } else { - let diff = SessionHistoryDiff::BrowsingContextDiff { + let diff = SessionHistoryDiff::BrowsingContext { browsing_context_id: change.browsing_context_id, new_reloader: NeedsToReload::No(change.new_pipeline_id), old_reloader: NeedsToReload::No(old_pipeline_id), @@ -4796,12 +4779,12 @@ where for diff in diffs_to_close { match diff { - SessionHistoryDiff::BrowsingContextDiff { new_reloader, .. } => { + SessionHistoryDiff::BrowsingContext { new_reloader, .. } => { if let Some(pipeline_id) = new_reloader.alive_pipeline_id() { pipelines_to_close.push(pipeline_id); } }, - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { pipeline_reloader, new_history_state_id, .. @@ -4890,7 +4873,7 @@ where .rev() .map(|diff| diff.alive_old_pipeline()) .skip(history_length) - .filter_map(|maybe_pipeline| maybe_pipeline) + .flatten() .collect::>(); // The future is stored with oldest entries front, so we must @@ -4902,7 +4885,7 @@ where .rev() .map(|diff| diff.alive_new_pipeline()) .skip(history_length) - .filter_map(|maybe_pipeline| maybe_pipeline), + .flatten(), ); pipelines_to_evict @@ -5171,7 +5154,7 @@ where .iter() .filter(|pipeline_id| **pipeline_id != pipeline.id); for id in pipeline_ids { - if let Some(pipeline) = self.pipelines.get(&id) { + if let Some(pipeline) = self.pipelines.get(id) { let _ = pipeline .event_loop .send(ConstellationControlMsg::ResizeInactive( diff --git a/components/constellation/event_loop.rs b/components/constellation/event_loop.rs index 7849cceb9c0..dacf55bfe24 100644 --- a/components/constellation/event_loop.rs +++ b/components/constellation/event_loop.rs @@ -31,7 +31,7 @@ impl EventLoop { /// Create a new event loop from the channel to its script thread. pub fn new(script_chan: IpcSender) -> Rc { Rc::new(EventLoop { - script_chan: script_chan, + script_chan, dont_send_or_sync: PhantomData, }) } diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index 8cf7b30fed3..f521b334f15 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -4,6 +4,9 @@ #![deny(unsafe_code)] +#[macro_use] +mod tracing; + mod browsingcontext; mod constellation; mod event_loop; diff --git a/components/constellation/network_listener.rs b/components/constellation/network_listener.rs index cddfff8dbfa..a3dd8c11027 100644 --- a/components/constellation/network_listener.rs +++ b/components/constellation/network_listener.rs @@ -54,7 +54,7 @@ impl NetworkListener { request_builder: self.request_builder.clone(), resource_threads: self.resource_threads.clone(), sender: self.sender.clone(), - pipeline_id: self.pipeline_id.clone(), + pipeline_id: self.pipeline_id, should_send: false, }; @@ -119,7 +119,7 @@ impl NetworkListener { self.request_builder.referrer = metadata .referrer .clone() - .map(|referrer_url| Referrer::ReferrerUrl(referrer_url)) + .map(Referrer::ReferrerUrl) .unwrap_or(Referrer::NoReferrer); self.request_builder.referrer_policy = metadata.referrer_policy; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 525fca57f79..fc6f038a5f1 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -2,6 +2,8 @@ * 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/. */ +#![allow(clippy::too_many_arguments)] + use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::rc::Rc; @@ -291,7 +293,7 @@ impl Pipeline { layout_to_constellation_chan: state.layout_to_constellation_chan, script_chan: script_chan.clone(), load_data: state.load_data.clone(), - script_port: script_port, + script_port, opts: (*opts::get()).clone(), prefs: prefs::pref_map().iter().collect(), pipeline_namespace_id: state.pipeline_namespace_id, @@ -311,7 +313,7 @@ impl Pipeline { let (bhm_control_chan, bhm_control_port) = ipc::channel().expect("Sampler chan"); unprivileged_pipeline_content.bhm_control_port = Some(bhm_control_port); - let _ = unprivileged_pipeline_content.spawn_multiprocess()?; + unprivileged_pipeline_content.spawn_multiprocess()?; Some(bhm_control_chan) } else { // Should not be None in single-process mode. @@ -358,16 +360,16 @@ impl Pipeline { load_data: LoadData, ) -> Pipeline { let pipeline = Pipeline { - id: id, - browsing_context_id: browsing_context_id, - top_level_browsing_context_id: top_level_browsing_context_id, - opener: opener, - event_loop: event_loop, - compositor_proxy: compositor_proxy, + id, + browsing_context_id, + top_level_browsing_context_id, + opener, + event_loop, + compositor_proxy, url: load_data.url.clone(), children: vec![], animation_state: AnimationState::NoAnimationsPresent, - load_data: load_data, + load_data, history_state_id: None, history_states: HashSet::new(), completely_loaded: false, @@ -426,8 +428,8 @@ impl Pipeline { /// The compositor's view of a pipeline. pub fn to_sendable(&self) -> CompositionPipeline { CompositionPipeline { - id: self.id.clone(), - top_level_browsing_context_id: self.top_level_browsing_context_id.clone(), + id: self.id, + top_level_browsing_context_id: self.top_level_browsing_context_id, script_chan: self.event_loop.sender(), } } @@ -445,13 +447,15 @@ impl Pipeline { .position(|id| *id == browsing_context_id) { None => { - return warn!( + warn!( "Pipeline remove child already removed ({:?}).", browsing_context_id - ); + ) }, - Some(index) => self.children.remove(index), - }; + Some(index) => { + self.children.remove(index); + }, + } } /// Notify the script thread that this pipeline is visible. @@ -539,13 +543,13 @@ impl UnprivilegedPipelineContent { devtools_chan: self.devtools_ipc_sender, window_size: self.window_size, pipeline_namespace_id: self.pipeline_namespace_id, - content_process_shutdown_chan: content_process_shutdown_chan, + content_process_shutdown_chan, webgl_chan: self.webgl_chan, webxr_registry: self.webxr_registry, webrender_document: self.webrender_document, webrender_api_sender: self.webrender_api_sender.clone(), player_context: self.player_context.clone(), - inherited_secure_context: self.load_data.inherited_secure_context.clone(), + inherited_secure_context: self.load_data.inherited_secure_context, }, layout_factory, self.font_cache_thread.clone(), diff --git a/components/constellation/sandboxing.rs b/components/constellation/sandboxing.rs index 5354d8c8a5d..c8cbb651ee8 100644 --- a/components/constellation/sandboxing.rs +++ b/components/constellation/sandboxing.rs @@ -28,6 +28,7 @@ use crate::pipeline::UnprivilegedPipelineContent; use crate::serviceworker::ServiceWorkerUnprivilegedContent; #[derive(Deserialize, Serialize)] +#[allow(clippy::large_enum_variant)] pub enum UnprivilegedContent { Pipeline(UnprivilegedPipelineContent), ServiceWorker(ServiceWorkerUnprivilegedContent), diff --git a/components/constellation/session_history.rs b/components/constellation/session_history.rs index b29d8635be7..9e6f765ee15 100644 --- a/components/constellation/session_history.rs +++ b/components/constellation/session_history.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cmp::PartialEq; -use std::{fmt, mem}; +use std::fmt; use euclid::Size2D; use log::debug; @@ -44,7 +44,7 @@ impl JointSessionHistory { pub fn push_diff(&mut self, diff: SessionHistoryDiff) -> Vec { debug!("pushing a past entry; removing future"); self.past.push(diff); - mem::replace(&mut self.future, vec![]) + std::mem::take(&mut self.future) } pub fn replace_reloader(&mut self, old_reloader: NeedsToReload, new_reloader: NeedsToReload) { @@ -59,12 +59,12 @@ impl JointSessionHistory { history_state_id: HistoryStateId, url: ServoUrl, ) { - if let Some(SessionHistoryDiff::PipelineDiff { + if let Some(SessionHistoryDiff::Pipeline { ref mut new_history_state_id, ref mut new_url, .. }) = self.past.iter_mut().find(|diff| match diff { - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { pipeline_reloader: NeedsToReload::No(id), .. } => pipeline_id == *id, @@ -74,12 +74,12 @@ impl JointSessionHistory { *new_url = url.clone(); } - if let Some(SessionHistoryDiff::PipelineDiff { + if let Some(SessionHistoryDiff::Pipeline { ref mut old_history_state_id, ref mut old_url, .. }) = self.future.iter_mut().find(|diff| match diff { - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { pipeline_reloader: NeedsToReload::No(id), .. } => pipeline_id == *id, @@ -93,14 +93,14 @@ impl JointSessionHistory { pub fn remove_entries_for_browsing_context(&mut self, context_id: BrowsingContextId) { debug!("{}: Removing entries for browsing context", context_id); self.past.retain(|diff| match diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, .. } => *browsing_context_id != context_id, _ => true, }); self.future.retain(|diff| match diff { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { browsing_context_id, .. } => *browsing_context_id != context_id, @@ -180,7 +180,7 @@ impl PartialEq for NeedsToReload { #[derive(Debug)] pub enum SessionHistoryDiff { /// Represents a diff where the active pipeline of an entry changed. - BrowsingContextDiff { + BrowsingContext { /// The browsing context whose pipeline changed browsing_context_id: BrowsingContextId, /// The previous pipeline (used when traversing into the past) @@ -189,7 +189,7 @@ pub enum SessionHistoryDiff { new_reloader: NeedsToReload, }, /// Represents a diff where the active state of a pipeline changed. - PipelineDiff { + Pipeline { /// The pipeline whose history state changed. pipeline_reloader: NeedsToReload, /// The old history state id. @@ -201,7 +201,7 @@ pub enum SessionHistoryDiff { /// The new url new_url: ServoUrl, }, - HashDiff { + Hash { pipeline_reloader: NeedsToReload, old_url: ServoUrl, new_url: ServoUrl, @@ -212,7 +212,7 @@ impl SessionHistoryDiff { /// Returns the old pipeline id if that pipeline is still alive, otherwise returns `None` pub fn alive_old_pipeline(&self) -> Option { match *self { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { ref old_reloader, .. } => match *old_reloader { NeedsToReload::No(pipeline_id) => Some(pipeline_id), @@ -225,7 +225,7 @@ impl SessionHistoryDiff { /// Returns the new pipeline id if that pipeline is still alive, otherwise returns `None` pub fn alive_new_pipeline(&self) -> Option { match *self { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { ref new_reloader, .. } => match *new_reloader { NeedsToReload::No(pipeline_id) => Some(pipeline_id), @@ -242,7 +242,7 @@ impl SessionHistoryDiff { reloader: &NeedsToReload, ) { match *self { - SessionHistoryDiff::BrowsingContextDiff { + SessionHistoryDiff::BrowsingContext { ref mut old_reloader, ref mut new_reloader, .. @@ -254,7 +254,7 @@ impl SessionHistoryDiff { *new_reloader = reloader.clone(); } }, - SessionHistoryDiff::PipelineDiff { + SessionHistoryDiff::Pipeline { ref mut pipeline_reloader, .. } => { @@ -262,7 +262,7 @@ impl SessionHistoryDiff { *pipeline_reloader = reloader.clone(); } }, - SessionHistoryDiff::HashDiff { + SessionHistoryDiff::Hash { ref mut pipeline_reloader, .. } => { diff --git a/components/constellation/timer_scheduler.rs b/components/constellation/timer_scheduler.rs index f56808b56f1..5e6071c8301 100644 --- a/components/constellation/timer_scheduler.rs +++ b/components/constellation/timer_scheduler.rs @@ -30,7 +30,7 @@ impl PartialOrd for ScheduledEvent { impl Eq for ScheduledEvent {} impl PartialEq for ScheduledEvent { fn eq(&self, other: &ScheduledEvent) -> bool { - self as *const ScheduledEvent == other as *const ScheduledEvent + std::ptr::eq(self, other) } } diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs new file mode 100644 index 00000000000..9c2cb995610 --- /dev/null +++ b/components/constellation/tracing.rs @@ -0,0 +1,261 @@ +/* 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/. */ + +/// Log an event from compositor at trace level. +/// - To disable tracing: RUST_LOG='constellation { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Log an event from script at trace level. +/// - To disable tracing: RUST_LOG='constellation { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Log an event from layout at trace level. +/// - To disable tracing: RUST_LOG='constellation { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Get the log target for an event, as a static string. +pub(crate) trait LogTarget { + fn log_target(&self) -> &'static str; +} + +mod from_compositor { + use super::LogTarget; + + macro_rules! target { + ($($name:literal)+) => { + concat!("constellation &'static str { + match self { + Self::Exit => target!("Exit"), + Self::GetBrowsingContext(_, _) => target!("GetBrowsingContext"), + Self::GetPipeline(_, _) => target!("GetPipeline"), + Self::GetFocusTopLevelBrowsingContext(_) => { + target!("GetFocusTopLevelBrowsingContext") + }, + Self::IsReadyToSaveImage(_) => target!("IsReadyToSaveImage"), + Self::Keyboard(_) => target!("Keyboard"), + Self::AllowNavigationResponse(_, _) => target!("AllowNavigationResponse"), + Self::LoadUrl(_, _) => target!("LoadUrl"), + Self::ClearCache => target!("ClearCache"), + Self::TraverseHistory(_, _) => target!("TraverseHistory"), + Self::WindowSize(_, _, _) => target!("WindowSize"), + Self::TickAnimation(_, _) => target!("TickAnimation"), + Self::WebDriverCommand(_) => target!("WebDriverCommand"), + Self::Reload(_) => target!("Reload"), + Self::LogEntry(_, _, _) => target!("LogEntry"), + Self::NewWebView(_, _) => target!("NewWebView"), + Self::CloseWebView(_) => target!("CloseWebView"), + Self::SendError(_, _) => target!("SendError"), + Self::FocusWebView(_) => target!("FocusWebView"), + Self::BlurWebView => target!("BlurWebView"), + Self::ForwardEvent(_, event) => event.log_target(), + Self::SetCursor(_) => target!("SetCursor"), + Self::EnableProfiler(_, _) => target!("EnableProfiler"), + Self::DisableProfiler => target!("DisableProfiler"), + Self::ExitFullScreen(_) => target!("ExitFullScreen"), + Self::MediaSessionAction(_) => target!("MediaSessionAction"), + Self::WebViewVisibilityChanged(_, _) => target!("WebViewVisibilityChanged"), + Self::IMEDismissed => target!("IMEDismissed"), + Self::ReadyToPresent(_) => target!("ReadyToPresent"), + Self::Gamepad(_) => target!("Gamepad"), + } + } + } + + impl LogTarget for script_traits::CompositorEvent { + fn log_target(&self) -> &'static str { + macro_rules! target_variant { + ($name:literal) => { + target!("ForwardEvent(" $name ")") + }; + } + match self { + Self::ResizeEvent(_, _) => target_variant!("ResizeEvent"), + Self::MouseButtonEvent(_, _, _, _, _, _) => target_variant!("MouseButtonEvent"), + Self::MouseMoveEvent(_, _, _) => target_variant!("MouseMoveEvent"), + Self::TouchEvent(_, _, _, _) => target_variant!("TouchEvent"), + Self::WheelEvent(_, _, _) => target_variant!("WheelEvent"), + Self::KeyboardEvent(_) => target_variant!("KeyboardEvent"), + Self::CompositionEvent(_) => target_variant!("CompositionEvent"), + Self::IMEDismissedEvent => target_variant!("IMEDismissedEvent"), + Self::GamepadEvent(_) => target_variant!("GamepadEvent"), + } + } + } +} + +mod from_script { + use super::LogTarget; + + macro_rules! target { + ($($name:literal)+) => { + concat!("constellation &'static str { + match self { + Self::CompleteMessagePortTransfer(_, _) => target!("CompleteMessagePortTransfer"), + Self::MessagePortTransferResult(_, _, _) => target!("MessagePortTransferResult"), + Self::NewMessagePort(_, _) => target!("NewMessagePort"), + Self::NewMessagePortRouter(_, _) => target!("NewMessagePortRouter"), + Self::RemoveMessagePortRouter(_) => target!("RemoveMessagePortRouter"), + Self::RerouteMessagePort(_, _) => target!("RerouteMessagePort"), + Self::MessagePortShipped(_) => target!("MessagePortShipped"), + Self::RemoveMessagePort(_) => target!("RemoveMessagePort"), + Self::EntanglePorts(_, _) => target!("EntanglePorts"), + Self::NewBroadcastChannelRouter(_, _, _) => target!("NewBroadcastChannelRouter"), + Self::RemoveBroadcastChannelRouter(_, _) => target!("RemoveBroadcastChannelRouter"), + Self::NewBroadcastChannelNameInRouter(_, _, _) => { + target!("NewBroadcastChannelNameInRouter") + }, + Self::RemoveBroadcastChannelNameInRouter(_, _, _) => { + target!("RemoveBroadcastChannelNameInRouter") + }, + Self::ScheduleBroadcast(_, _) => target!("ScheduleBroadcast"), + Self::ForwardToEmbedder(msg) => msg.log_target(), + Self::InitiateNavigateRequest(_, _) => target!("InitiateNavigateRequest"), + Self::BroadcastStorageEvent(_, _, _, _, _) => target!("BroadcastStorageEvent"), + Self::ChangeRunningAnimationsState(_) => target!("ChangeRunningAnimationsState"), + Self::CreateCanvasPaintThread(_, _) => target!("CreateCanvasPaintThread"), + Self::Focus => target!("Focus"), + Self::GetTopForBrowsingContext(_, _) => target!("GetTopForBrowsingContext"), + Self::GetBrowsingContextInfo(_, _) => target!("GetBrowsingContextInfo"), + Self::GetChildBrowsingContextId(_, _, _) => target!("GetChildBrowsingContextId"), + Self::LoadComplete => target!("LoadComplete"), + Self::LoadUrl(_, _) => target!("LoadUrl"), + Self::AbortLoadUrl => target!("AbortLoadUrl"), + Self::PostMessage { .. } => target!("PostMessage"), + Self::NavigatedToFragment(_, _) => target!("NavigatedToFragment"), + Self::TraverseHistory(_) => target!("TraverseHistory"), + Self::PushHistoryState(_, _) => target!("PushHistoryState"), + Self::ReplaceHistoryState(_, _) => target!("ReplaceHistoryState"), + Self::JointSessionHistoryLength(_) => target!("JointSessionHistoryLength"), + Self::RemoveIFrame(_, _) => target!("RemoveIFrame"), + Self::VisibilityChangeComplete(_) => target!("VisibilityChangeComplete"), + Self::ScriptLoadedURLInIFrame(_) => target!("ScriptLoadedURLInIFrame"), + Self::ScriptNewIFrame(_) => target!("ScriptNewIFrame"), + Self::ScriptNewAuxiliary(_) => target!("ScriptNewAuxiliary"), + Self::ActivateDocument => target!("ActivateDocument"), + Self::SetDocumentState(_) => target!("SetDocumentState"), + Self::SetLayoutEpoch(_, _) => target!("SetLayoutEpoch"), + Self::SetFinalUrl(_) => target!("SetFinalUrl"), + Self::TouchEventProcessed(_) => target!("TouchEventProcessed"), + Self::LogEntry(_, _) => target!("LogEntry"), + Self::DiscardDocument => target!("DiscardDocument"), + Self::DiscardTopLevelBrowsingContext => target!("DiscardTopLevelBrowsingContext"), + Self::PipelineExited => target!("PipelineExited"), + Self::ForwardDOMMessage(_, _) => target!("ForwardDOMMessage"), + Self::ScheduleJob(_) => target!("ScheduleJob"), + Self::GetClientWindow(_) => target!("GetClientWindow"), + Self::GetScreenSize(_) => target!("GetScreenSize"), + Self::GetScreenAvailSize(_) => target!("GetScreenAvailSize"), + Self::MediaSessionEvent(_, _) => target!("MediaSessionEvent"), + Self::RequestAdapter(_, _, _) => target!("RequestAdapter"), + Self::GetWebGPUChan(_) => target!("GetWebGPUChan"), + Self::TitleChanged(_, _) => target!("TitleChanged"), + } + } + } + + impl LogTarget for embedder_traits::EmbedderMsg { + fn log_target(&self) -> &'static str { + macro_rules! target_variant { + ($name:literal) => { + target!("ForwardToEmbedder(" $name ")") + }; + } + match self { + Self::Status(_) => target_variant!("Status"), + Self::ChangePageTitle(_) => target_variant!("ChangePageTitle"), + Self::MoveTo(_) => target_variant!("MoveTo"), + Self::ResizeTo(_) => target_variant!("ResizeTo"), + Self::Prompt(_, _) => target_variant!("Prompt"), + Self::ShowContextMenu(_, _, _) => target_variant!("ShowContextMenu"), + Self::AllowNavigationRequest(_, _) => target_variant!("AllowNavigationRequest"), + Self::AllowOpeningWebView(_) => target_variant!("AllowOpeningWebView"), + Self::WebViewOpened(_) => target_variant!("WebViewOpened"), + Self::WebViewClosed(_) => target_variant!("WebViewClosed"), + Self::WebViewFocused(_) => target_variant!("WebViewFocused"), + Self::WebViewBlurred => target_variant!("WebViewBlurred"), + Self::AllowUnload(_) => target_variant!("AllowUnload"), + Self::Keyboard(_) => target_variant!("Keyboard"), + Self::GetClipboardContents(_) => target_variant!("GetClipboardContents"), + Self::SetClipboardContents(_) => target_variant!("SetClipboardContents"), + Self::SetCursor(_) => target_variant!("SetCursor"), + Self::NewFavicon(_) => target_variant!("NewFavicon"), + Self::HeadParsed => target_variant!("HeadParsed"), + Self::HistoryChanged(_, _) => target_variant!("HistoryChanged"), + Self::SetFullscreenState(_) => target_variant!("SetFullscreenState"), + Self::LoadStart => target_variant!("LoadStart"), + Self::LoadComplete => target_variant!("LoadComplete"), + Self::Panic(_, _) => target_variant!("Panic"), + Self::GetSelectedBluetoothDevice(_, _) => { + target_variant!("GetSelectedBluetoothDevice") + }, + Self::SelectFiles(_, _, _) => target_variant!("SelectFiles"), + Self::PromptPermission(_, _) => target_variant!("PromptPermission"), + Self::ShowIME(_, _, _, _) => target_variant!("ShowIME"), + Self::HideIME => target_variant!("HideIME"), + Self::Shutdown => target_variant!("Shutdown"), + Self::ReportProfile(_) => target_variant!("ReportProfile"), + Self::MediaSessionEvent(_) => target_variant!("MediaSessionEvent"), + Self::OnDevtoolsStarted(_, _) => target_variant!("OnDevtoolsStarted"), + Self::ReadyToPresent => target_variant!("ReadyToPresent"), + Self::EventDelivered(_) => target_variant!("EventDelivered"), + } + } + } +} + +mod from_layout { + use super::LogTarget; + + macro_rules! target { + ($($name:literal)+) => { + concat!("constellation &'static str { + match self { + Self::IFrameSizes(_) => target!("IFrameSizes"), + Self::PendingPaintMetric(_, _) => target!("PendingPaintMetric"), + } + } + } +} diff --git a/components/dom_struct/lib.rs b/components/dom_struct/lib.rs index 3cafbb48731..31b41459ebb 100644 --- a/components/dom_struct/lib.rs +++ b/components/dom_struct/lib.rs @@ -20,13 +20,13 @@ pub fn dom_struct(args: TokenStream, input: TokenStream) -> TokenStream { // Work around https://github.com/rust-lang/rust/issues/46489 let attributes: TokenStream = attributes.to_string().parse().unwrap(); - let output: TokenStream = attributes.into_iter().chain(input.into_iter()).collect(); + let output: TokenStream = attributes.into_iter().chain(input).collect(); let item: Item = syn::parse(output).unwrap(); if let Item::Struct(s) = item { let s2 = s.clone(); - if s.generics.params.len() > 0 { + if !s.generics.params.is_empty() { return quote!(#s2).into(); } if let Fields::Named(ref f) = s.fields { diff --git a/components/domobject_derive/lib.rs b/components/domobject_derive/lib.rs index f15cc0be971..81c9b89be79 100644 --- a/components/domobject_derive/lib.rs +++ b/components/domobject_derive/lib.rs @@ -4,7 +4,6 @@ #![recursion_limit = "128"] -use proc_macro2; use quote::{quote, TokenStreamExt}; use syn::parse_quote; diff --git a/components/geometry/lib.rs b/components/geometry/lib.rs index 54ccd67d109..25ce5cfceaf 100644 --- a/components/geometry/lib.rs +++ b/components/geometry/lib.rs @@ -51,7 +51,7 @@ impl MaxRect for Rect { impl MaxRect for LayoutRect { #[inline] fn max_rect() -> LayoutRect { - LayoutRect::new( + LayoutRect::from_origin_and_size( LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0), LayoutSize::new(f32::MAX, f32::MAX), ) diff --git a/components/gfx/font.rs b/components/gfx/font.rs index 9fd25b839d0..6916b2e5261 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -24,6 +24,7 @@ use style::values::computed::font::{GenericFontFamily, SingleFontFamily}; use unicode_script::Script; use webrender_api::FontInstanceKey; +use crate::font_cache_thread::FontIdentifier; use crate::font_context::{FontContext, FontSource}; use crate::font_template::FontTemplateDescriptor; use crate::platform::font::{FontHandle, FontTable}; @@ -58,7 +59,7 @@ pub trait FontHandleMethods: Sized { fctx: &FontContextHandle, template: Arc, pt_size: Option, - ) -> Result; + ) -> Result; fn template(&self) -> Arc; fn family_name(&self) -> Option; @@ -78,7 +79,7 @@ pub trait FontHandleMethods: Sized { fn table_for_tag(&self, _: FontTableTag) -> Option; /// A unique identifier for the font, allowing comparison. - fn identifier(&self) -> Atom; + fn identifier(&self) -> &FontIdentifier; } // Used to abstract over the shaper's choice of fixed int representation. @@ -96,7 +97,7 @@ impl FontTableTagConversions for FontTableTag { (self >> 24) as u8, (self >> 16) as u8, (self >> 8) as u8, - (self >> 0) as u8, + *self as u8, ]; str::from_utf8(&bytes).unwrap().to_owned() } @@ -190,7 +191,7 @@ impl Font { let metrics = handle.metrics(); Font { - handle: handle, + handle, shaper: None, descriptor, metrics, @@ -202,7 +203,7 @@ impl Font { } /// A unique identifier for the font, allowing comparison. - pub fn identifier(&self) -> Atom { + pub fn identifier(&self) -> &FontIdentifier { self.handle.identifier() } } @@ -403,7 +404,7 @@ impl FontGroup { .font_family .families .iter() - .map(|family| FontGroupFamily::new(descriptor.clone(), &family)) + .map(|family| FontGroupFamily::new(descriptor.clone(), family)) .collect(); FontGroup { @@ -419,7 +420,7 @@ impl FontGroup { /// found, returns None. pub fn find_by_codepoint( &mut self, - mut font_context: &mut FontContext, + font_context: &mut FontContext, codepoint: char, ) -> Option { let should_look_for_small_caps = self.descriptor.variant == font_variant_caps::T::SmallCaps && @@ -436,43 +437,40 @@ impl FontGroup { let has_glyph = |font: &FontRef| font.borrow().has_glyph_for(codepoint); - if let Some(font) = self.find(&mut font_context, |font| has_glyph(font)) { + if let Some(font) = self.find(font_context, has_glyph) { return font_or_synthesized_small_caps(font); } if let Some(ref last_matching_fallback) = self.last_matching_fallback { - if has_glyph(&last_matching_fallback) { + if has_glyph(last_matching_fallback) { return font_or_synthesized_small_caps(last_matching_fallback.clone()); } } - if let Some(font) = self.find_fallback(&mut font_context, Some(codepoint), has_glyph) { + if let Some(font) = self.find_fallback(font_context, Some(codepoint), has_glyph) { self.last_matching_fallback = Some(font.clone()); return font_or_synthesized_small_caps(font); } - self.first(&mut font_context) + self.first(font_context) } /// Find the first available font in the group, or the first available fallback font. - pub fn first( - &mut self, - mut font_context: &mut FontContext, - ) -> Option { - self.find(&mut font_context, |_| true) - .or_else(|| self.find_fallback(&mut font_context, None, |_| true)) + pub fn first(&mut self, font_context: &mut FontContext) -> Option { + self.find(font_context, |_| true) + .or_else(|| self.find_fallback(font_context, None, |_| true)) } /// Find a font which returns true for `predicate`. This method mutates because we may need to /// load new font data in the process of finding a suitable font. - fn find(&mut self, mut font_context: &mut FontContext, predicate: P) -> Option + fn find(&mut self, font_context: &mut FontContext, predicate: P) -> Option where S: FontSource, P: FnMut(&FontRef) -> bool, { self.families .iter_mut() - .filter_map(|family| family.font(&mut font_context)) + .filter_map(|family| family.font(font_context)) .find(predicate) } @@ -567,8 +565,7 @@ impl RunMetrics { } pub fn get_and_reset_text_shaping_performance_counter() -> usize { - let value = TEXT_SHAPING_PERFORMANCE_COUNTER.swap(0, Ordering::SeqCst); - value + TEXT_SHAPING_PERFORMANCE_COUNTER.swap(0, Ordering::SeqCst) } /// The scope within which we will look for a font. diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index bc8e7680417..aaa5f629d13 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -17,8 +17,10 @@ use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg}; use serde::{Deserialize, Serialize}; use servo_atoms::Atom; use servo_url::ServoUrl; -use style::font_face::{EffectiveSources, Source}; -use style::values::computed::font::FamilyName; +use style::font_face::{FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source}; +use style::media_queries::Device; +use style::shared_lock::SharedRwLockReadGuard; +use style::stylesheets::{Stylesheet, StylesheetInDocument}; use webrender_api::{FontInstanceKey, FontKey}; use crate::font::{FontFamilyDescriptor, FontFamilyName, FontSearchScope}; @@ -26,11 +28,13 @@ use crate::font_context::FontSource; use crate::font_template::{FontTemplate, FontTemplateDescriptor}; use crate::platform::font_context::FontContextHandle; use crate::platform::font_list::{ - for_each_available_family, for_each_variation, system_default_family, SANS_SERIF_FONT_FAMILY, + for_each_available_family, for_each_variation, system_default_family, LocalFontIdentifier, + SANS_SERIF_FONT_FAMILY, }; use crate::platform::font_template::FontTemplateData; /// A list of font templates that make up a given font family. +#[derive(Default)] pub struct FontTemplates { templates: Vec, } @@ -47,9 +51,15 @@ pub struct SerializedFontTemplateInfo { pub font_key: FontKey, } +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum FontIdentifier { + Local(LocalFontIdentifier), + Web(ServoUrl), +} + #[derive(Debug, Deserialize, Serialize)] pub struct SerializedFontTemplate { - identifier: Atom, + identifier: FontIdentifier, bytes_receiver: ipc_channel::ipc::IpcBytesReceiver, } @@ -61,10 +71,6 @@ impl SerializedFontTemplate { } impl FontTemplates { - pub fn new() -> FontTemplates { - FontTemplates { templates: vec![] } - } - /// Find a font in this family that matches a given descriptor. pub fn find_font_for_style( &mut self, @@ -111,7 +117,7 @@ impl FontTemplates { None } - pub fn add_template(&mut self, identifier: Atom, maybe_data: Option>) { + pub fn add_template(&mut self, identifier: FontIdentifier, maybe_data: Option>) { for template in &self.templates { if *template.identifier() == identifier { return; @@ -133,7 +139,7 @@ pub enum Command { IpcSender, ), GetFontInstance(FontKey, Au, IpcSender), - AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>), + AddWebFont(LowercaseString, Vec, IpcSender<()>), AddDownloadedWebFont(LowercaseString, ServoUrl, Vec, IpcSender<()>), Exit(IpcSender<()>), Ping, @@ -156,7 +162,7 @@ struct FontCache { font_context: FontContextHandle, core_resource_thread: CoreResourceThread, webrender_api: Box, - webrender_fonts: HashMap, + webrender_fonts: HashMap, font_instances: HashMap<(FontKey, Au), FontInstanceKey>, } @@ -214,7 +220,7 @@ impl FontCache { font_key: font_template_info.font_key, }, ))); - let _ = bytes_sender.send(&*font_template_info.font_template.bytes()); + let _ = bytes_sender.send(&font_template_info.font_template.bytes()); }, }; }, @@ -236,7 +242,7 @@ impl FontCache { }, Command::AddDownloadedWebFont(family_name, url, bytes, result) => { let templates = &mut self.web_families.get_mut(&family_name).unwrap(); - templates.add_template(Atom::from(url.to_string()), Some(bytes)); + templates.add_template(FontIdentifier::Web(url), Some(bytes)); drop(result.send(())); }, Command::Ping => (), @@ -251,10 +257,10 @@ impl FontCache { fn handle_add_web_font( &mut self, family_name: LowercaseString, - mut sources: EffectiveSources, + mut sources: Vec, sender: IpcSender<()>, ) { - let src = if let Some(src) = sources.next() { + let src = if let Some(src) = sources.pop() { src } else { sender.send(()).unwrap(); @@ -262,7 +268,7 @@ impl FontCache { }; if !self.web_families.contains_key(&family_name) { - let templates = FontTemplates::new(); + let templates = FontTemplates::default(); self.web_families.insert(family_name.clone(), templates); } @@ -298,7 +304,7 @@ impl FontCache { FetchResponseMsg::ProcessResponseChunk(new_bytes) => { trace!("@font-face {} chunk={:?}", family_name, new_bytes); if *response_valid.lock().unwrap() { - bytes.lock().unwrap().extend(new_bytes.into_iter()) + bytes.lock().unwrap().extend(new_bytes) } }, FetchResponseMsg::ProcessResponseEOF(response) => { @@ -312,7 +318,7 @@ impl FontCache { channel_to_self.send(msg).unwrap(); return; } - let bytes = mem::replace(&mut *bytes.lock().unwrap(), vec![]); + let bytes = mem::take(&mut *bytes.lock().unwrap()); trace!("@font-face {} data={:?}", family_name, bytes); let bytes = match fontsan::process(&bytes) { Ok(san) => san, @@ -347,9 +353,9 @@ impl FontCache { let font_face_name = LowercaseString::new(&font.name); let templates = &mut self.web_families.get_mut(&family_name).unwrap(); let mut found = false; - for_each_variation(&font_face_name, |path| { + for_each_variation(&font_face_name, |local_font_identifier| { found = true; - templates.add_template(Atom::from(&*path), None); + templates.add_template(FontIdentifier::Local(local_font_identifier), None); }); if found { sender.send(()).unwrap(); @@ -365,10 +371,7 @@ impl FontCache { self.local_families.clear(); for_each_available_family(|family_name| { let family_name = LowercaseString::new(&family_name); - if !self.local_families.contains_key(&family_name) { - let templates = FontTemplates::new(); - self.local_families.insert(family_name, templates); - } + self.local_families.entry(family_name).or_default(); }); } @@ -393,8 +396,8 @@ impl FontCache { let s = self.local_families.get_mut(&family_name).unwrap(); if s.templates.is_empty() { - for_each_variation(&family_name, |path| { - s.add_template(Atom::from(&*path), None); + for_each_variation(&family_name, |local_font_identifier| { + s.add_template(FontIdentifier::Local(local_font_identifier), None); }); } @@ -434,16 +437,16 @@ impl FontCache { .entry(template.identifier.clone()) .or_insert_with(|| { let font = match (template.bytes_if_in_memory(), template.native_font()) { - (Some(bytes), _) => FontData::Raw(bytes), + (Some(bytes), _) => FontData::Raw((*bytes).clone()), (None, Some(native_font)) => FontData::Native(native_font), - (None, None) => FontData::Raw(template.bytes()), + (None, None) => FontData::Raw((*template.bytes()).clone()), }; webrender_api.add_font(font) }); FontTemplateInfo { font_template: template, - font_key: font_key, + font_key, } } @@ -454,13 +457,13 @@ impl FontCache { ) -> Option { match family_descriptor.scope { FontSearchScope::Any => self - .find_font_in_web_family(&template_descriptor, &family_descriptor.name) + .find_font_in_web_family(template_descriptor, &family_descriptor.name) .or_else(|| { - self.find_font_in_local_family(&template_descriptor, &family_descriptor.name) + self.find_font_in_local_family(template_descriptor, &family_descriptor.name) }), FontSearchScope::Local => { - self.find_font_in_local_family(&template_descriptor, &family_descriptor.name) + self.find_font_in_local_family(template_descriptor, &family_descriptor.name) }, } .map(|t| self.get_font_template_info(t)) @@ -489,12 +492,12 @@ impl FontCacheThread { let generic_fonts = populate_generic_fonts(); let mut cache = FontCache { - port: port, + port, channel_to_self, generic_fonts, local_families: HashMap::new(), web_families: HashMap::new(), - font_context: FontContextHandle::new(), + font_context: FontContextHandle::default(), core_resource_thread, webrender_api, webrender_fonts: HashMap::new(), @@ -506,22 +509,61 @@ impl FontCacheThread { }) .expect("Thread spawning failed"); - FontCacheThread { chan: chan } + FontCacheThread { chan } } - pub fn add_web_font( + pub fn add_all_web_fonts_from_stylesheet( &self, - family: FamilyName, - sources: EffectiveSources, - sender: IpcSender<()>, - ) { - self.chan - .send(Command::AddWebFont( - LowercaseString::new(&family.name), - sources, - sender, - )) - .unwrap(); + stylesheet: &Stylesheet, + guard: &SharedRwLockReadGuard, + device: &Device, + font_cache_sender: &IpcSender<()>, + synchronous: bool, + ) -> usize { + let (sender, receiver) = if synchronous { + let (sender, receiver) = ipc::channel().unwrap(); + (Some(sender), Some(receiver)) + } else { + (None, None) + }; + + let mut number_loading = 0; + stylesheet.effective_font_face_rules(device, guard, |rule| { + let font_face = match rule.font_face() { + Some(font_face) => font_face, + None => return, + }; + + let sources: Vec = font_face + .sources() + .0 + .iter() + .rev() + .filter(is_supported_web_font_source) + .cloned() + .collect(); + if sources.is_empty() { + return; + } + + let sender = sender.as_ref().unwrap_or(font_cache_sender).clone(); + self.chan + .send(Command::AddWebFont( + LowercaseString::new(&font_face.family().name), + sources, + sender, + )) + .unwrap(); + + // Either increment the count of loading web fonts, or wait for a synchronous load. + if let Some(ref receiver) = receiver { + receiver.recv().unwrap(); + } else { + number_loading += 1; + } + }); + + number_loading } pub fn exit(&self) { @@ -621,7 +663,7 @@ impl Deref for LowercaseString { #[inline] fn deref(&self) -> &str { - &*self.inner + &self.inner } } @@ -630,3 +672,31 @@ impl fmt::Display for LowercaseString { self.inner.fmt(f) } } + +fn is_supported_web_font_source(source: &&Source) -> bool { + let url_source = match source { + Source::Url(ref url_source) => url_source, + Source::Local(_) => return true, + }; + let format_hint = match url_source.format_hint { + Some(ref format_hint) => format_hint, + None => return true, + }; + + if matches!( + format_hint, + FontFaceSourceFormat::Keyword( + FontFaceSourceFormatKeyword::Truetype | + FontFaceSourceFormatKeyword::Opentype | + FontFaceSourceFormatKeyword::Woff + ) + ) { + return true; + } + + if let FontFaceSourceFormat::String(string) = format_hint { + return string == "truetype" || string == "opentype" || string == "woff"; + } + + false +} diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 3a577a1fbd1..2febda51d78 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -65,7 +65,7 @@ pub struct FontContext { impl FontContext { pub fn new(font_source: S) -> FontContext { - let handle = FontContextHandle::new(); + let handle = FontContextHandle::default(); FontContext { platform_handle: handle, font_source, @@ -99,8 +99,8 @@ impl FontContext { style, }; - if let Some(ref font_group) = self.font_group_cache.get(&cache_key) { - return (*font_group).clone(); + if let Some(font_group) = self.font_group_cache.get(&cache_key) { + return font_group.clone(); } let font_group = Rc::new(RefCell::new(FontGroup::new(&cache_key.style))); @@ -150,30 +150,27 @@ impl FontContext { family_descriptor: family_descriptor.clone(), }; - self.font_cache - .get(&cache_key) - .map(|v| v.clone()) - .unwrap_or_else(|| { - debug!( - "FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}", - font_descriptor, family_descriptor - ); + self.font_cache.get(&cache_key).cloned().unwrap_or_else(|| { + debug!( + "FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}", + font_descriptor, family_descriptor + ); - let font = self - .font_template(&font_descriptor.template_descriptor, family_descriptor) - .and_then(|template_info| { - self.create_font( - template_info, - font_descriptor.to_owned(), - synthesized_small_caps_font, - ) - .ok() - }) - .map(|font| Rc::new(RefCell::new(font))); + let font = self + .font_template(&font_descriptor.template_descriptor, family_descriptor) + .and_then(|template_info| { + self.create_font( + template_info, + font_descriptor.to_owned(), + synthesized_small_caps_font, + ) + .ok() + }) + .map(|font| Rc::new(RefCell::new(font))); - self.font_cache.insert(cache_key, font.clone()); - font - }) + self.font_cache.insert(cache_key, font.clone()); + font + }) } fn font_template( @@ -182,11 +179,11 @@ impl FontContext { family_descriptor: &FontFamilyDescriptor, ) -> Option { let cache_key = FontTemplateCacheKey { - template_descriptor: template_descriptor.clone(), + template_descriptor: *template_descriptor, family_descriptor: family_descriptor.clone(), }; - self.font_template_cache.get(&cache_key).map(|v| v.clone()).unwrap_or_else(|| { + self.font_template_cache.get(&cache_key).cloned().unwrap_or_else(|| { debug!( "FontContext::font_template cache miss for template_descriptor={:?} family_descriptor={:?}", template_descriptor, @@ -194,7 +191,7 @@ impl FontContext { ); let template_info = self.font_source.font_template( - template_descriptor.clone(), + *template_descriptor, family_descriptor.clone(), ); @@ -210,7 +207,7 @@ impl FontContext { info: FontTemplateInfo, descriptor: FontDescriptor, synthesized_small_caps: Option, - ) -> Result { + ) -> Result { let handle = FontHandle::new_from_template( &self.platform_handle, info.font_template, diff --git a/components/gfx/font_template.rs b/components/gfx/font_template.rs index 3ac7026c29a..00d95159632 100644 --- a/components/gfx/font_template.rs +++ b/components/gfx/font_template.rs @@ -7,13 +7,13 @@ use std::io::Error as IoError; use std::sync::{Arc, Weak}; use serde::{Deserialize, Serialize}; -use servo_atoms::Atom; use style::computed_values::font_stretch::T as FontStretch; use style::computed_values::font_style::T as FontStyle; use style::properties::style_structs::Font as FontStyleStruct; use style::values::computed::font::FontWeight; use crate::font::FontHandleMethods; +use crate::font_cache_thread::FontIdentifier; use crate::platform::font::FontHandle; use crate::platform::font_context::FontContextHandle; use crate::platform::font_template::FontTemplateData; @@ -85,7 +85,7 @@ impl<'a> From<&'a FontStyleStruct> for FontTemplateDescriptor { /// font instance handles. It contains a unique /// FontTemplateData structure that is platform specific. pub struct FontTemplate { - identifier: Atom, + identifier: FontIdentifier, descriptor: Option, weak_ref: Option>, // GWTODO: Add code path to unset the strong_ref for web fonts! @@ -103,24 +103,21 @@ impl Debug for FontTemplate { /// is common, regardless of the number of instances of /// this font handle per thread. impl FontTemplate { - pub fn new(identifier: Atom, maybe_bytes: Option>) -> Result { + pub fn new( + identifier: FontIdentifier, + maybe_bytes: Option>, + ) -> Result { let maybe_data = match maybe_bytes { Some(_) => Some(FontTemplateData::new(identifier.clone(), maybe_bytes)?), None => None, }; - let maybe_strong_ref = match maybe_data { - Some(data) => Some(Arc::new(data)), - None => None, - }; + let maybe_strong_ref = maybe_data.map(Arc::new); - let maybe_weak_ref = match maybe_strong_ref { - Some(ref strong_ref) => Some(Arc::downgrade(strong_ref)), - None => None, - }; + let maybe_weak_ref = maybe_strong_ref.as_ref().map(Arc::downgrade); Ok(FontTemplate { - identifier: identifier, + identifier, descriptor: None, weak_ref: maybe_weak_ref, strong_ref: maybe_strong_ref, @@ -128,7 +125,7 @@ impl FontTemplate { }) } - pub fn identifier(&self) -> &Atom { + pub fn identifier(&self) -> &FontIdentifier { &self.identifier } @@ -161,7 +158,7 @@ impl FontTemplate { fctx: &FontContextHandle, requested_desc: &FontTemplateDescriptor, ) -> Option> { - self.descriptor(&fctx).and_then(|descriptor| { + self.descriptor(fctx).and_then(|descriptor| { if *requested_desc == descriptor { self.data().ok() } else { @@ -177,23 +174,22 @@ impl FontTemplate { font_context: &FontContextHandle, requested_descriptor: &FontTemplateDescriptor, ) -> Option<(Arc, f32)> { - self.descriptor(&font_context).and_then(|descriptor| { + self.descriptor(font_context).and_then(|descriptor| { self.data() .ok() .map(|data| (data, descriptor.distance_from(requested_descriptor))) }) } - fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), ()> { + fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), &'static str> { if !self.is_valid { - return Err(()); + return Err("Invalid font template"); } - let data = self.data().map_err(|_| ())?; - let handle: Result = - FontHandleMethods::new_from_template(font_context, data, None); + let data = self.data().map_err(|_| "Could not get FontTemplate data")?; + let handle = FontHandleMethods::new_from_template(font_context, data, None); self.is_valid = handle.is_ok(); - let handle = handle?; + let handle: FontHandle = handle?; self.descriptor = Some(FontTemplateDescriptor::new( handle.boldness(), handle.stretchiness(), diff --git a/components/gfx/platform/freetype/android/font_list.rs b/components/gfx/platform/freetype/android/font_list.rs index 44c6640468c..968cb460589 100644 --- a/components/gfx/platform/freetype/android/font_list.rs +++ b/components/gfx/platform/freetype/android/font_list.rs @@ -5,6 +5,8 @@ use std::path::Path; use log::warn; +use serde::{Deserialize, Serialize}; +use style::Atom; use ucd::{Codepoint, UnicodeBlock}; use super::xml::{Attribute, Node}; @@ -14,6 +16,13 @@ lazy_static::lazy_static! { static ref FONT_LIST: FontList = FontList::new(); } +/// An identifier for a local font on Android systems. +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct LocalFontIdentifier { + /// The path to the font. + pub path: Atom, +} + // Android doesn't provide an API to query system fonts until Android O: // https://developer.android.com/reference/android/text/FontConfig.html // System font configuration files must be parsed until Android O version is set as the minimum target. @@ -426,11 +435,17 @@ where pub fn for_each_variation(family_name: &str, mut callback: F) where - F: FnMut(String), + F: FnMut(LocalFontIdentifier), { + let mut produce_font = |font: &Font| { + callback(LocalFontIdentifier { + path: Atom::from(FontList::font_absolute_path(&font.filename)), + }) + }; + if let Some(family) = FONT_LIST.find_family(family_name) { for font in &family.fonts { - callback(FontList::font_absolute_path(&font.filename)); + produce_font(font); } return; } @@ -439,12 +454,8 @@ where if let Some(family) = FONT_LIST.find_family(&alias.to) { for font in &family.fonts { match (alias.weight, font.weight) { - (None, _) => callback(FontList::font_absolute_path(&font.filename)), - (Some(w1), Some(w2)) => { - if w1 == w2 { - callback(FontList::font_absolute_path(&font.filename)) - } - }, + (None, _) => produce_font(font), + (Some(w1), Some(w2)) if w1 == w2 => produce_font(font), _ => {}, } } diff --git a/components/gfx/platform/freetype/font.rs b/components/gfx/platform/freetype/font.rs index a0de645a544..024b3c563e1 100644 --- a/components/gfx/platform/freetype/font.rs +++ b/components/gfx/platform/freetype/font.rs @@ -17,7 +17,6 @@ use freetype::freetype::{ use freetype::succeeded; use freetype::tt_os2::TT_OS2; use log::debug; -use servo_atoms::Atom; use style::computed_values::font_stretch::T as FontStretch; use style::computed_values::font_weight::T as FontWeight; use style::values::computed::font::FontStyle; @@ -27,6 +26,7 @@ use crate::font::{ FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, GPOS, GSUB, KERN, }; +use crate::font_cache_thread::FontIdentifier; use crate::platform::font_context::FontContextHandle; use crate::platform::font_template::FontTemplateData; use crate::text::glyph::GlyphId; @@ -97,36 +97,39 @@ fn create_face( lib: FT_Library, template: &FontTemplateData, pt_size: Option, -) -> Result { +) -> Result { unsafe { let mut face: FT_Face = ptr::null_mut(); let face_index = 0 as FT_Long; - let result = if let Some(ref bytes) = template.bytes { - FT_New_Memory_Face( - lib, - bytes.as_ptr(), - bytes.len() as FT_Long, - face_index, - &mut face, - ) - } else { - // This will trigger a synchronous file read during layout, which we may want to - // revisit at some point. See discussion here: - // - // https://github.com/servo/servo/pull/20506#issuecomment-378838800 - - let filename = - CString::new(&*template.identifier).expect("filename contains NUL byte!"); - FT_New_Face(lib, filename.as_ptr(), face_index, &mut face) + let result = match template.identifier { + FontIdentifier::Web(_) => { + let bytes = template.bytes(); + FT_New_Memory_Face( + lib, + bytes.as_ptr(), + bytes.len() as FT_Long, + face_index, + &mut face, + ) + }, + FontIdentifier::Local(ref local_identifier) => { + // This will trigger a synchronous file read during layout, which we may want to + // revisit at some point. See discussion here: + // + // https://github.com/servo/servo/pull/20506#issuecomment-378838800 + let filename = + CString::new(&*local_identifier.path).expect("filename contains NUL byte!"); + FT_New_Face(lib, filename.as_ptr(), face_index, &mut face) + }, }; if !succeeded(result) || face.is_null() { - return Err(()); + return Err("Could not create FreeType face"); } if let Some(s) = pt_size { - FontHandle::set_char_size(face, s).or(Err(()))? + FontHandle::set_char_size(face, s)? } Ok(face) @@ -138,16 +141,16 @@ impl FontHandleMethods for FontHandle { fctx: &FontContextHandle, template: Arc, pt_size: Option, - ) -> Result { + ) -> Result { let ft_ctx: FT_Library = fctx.ctx.ctx; if ft_ctx.is_null() { - return Err(()); + return Err("Null FT_Library"); } let face = create_face(ft_ctx, &template, pt_size)?; let mut handle = FontHandle { - face: face, + face, font_data: template, context_handle: fctx.clone(), can_do_fast_shaping: false, @@ -264,7 +267,7 @@ impl FontHandleMethods for FontHandle { let res = FT_Load_Glyph(self.face, glyph as FT_UInt, GLYPH_LOAD_FLAGS); if succeeded(res) { let void_glyph = (*self.face).glyph; - let slot: FT_GlyphSlot = mem::transmute(void_glyph); + let slot: FT_GlyphSlot = void_glyph; assert!(!slot.is_null()); let advance = (*slot).metrics.horiAdvance; debug!("h_advance for {} is {}", glyph, advance); @@ -313,17 +316,17 @@ impl FontHandleMethods for FontHandle { .map_or(max_advance, |advance| self.font_units_to_au(advance)); let metrics = FontMetrics { - underline_size: underline_size, - underline_offset: underline_offset, - strikeout_size: strikeout_size, - strikeout_offset: strikeout_offset, - leading: leading, - x_height: x_height, - em_size: em_size, - ascent: ascent, + underline_size, + underline_offset, + strikeout_size, + strikeout_offset, + leading, + x_height, + em_size, + ascent, descent: -descent, // linux font's seem to use the opposite sign from mac - max_advance: max_advance, - average_advance: average_advance, + max_advance, + average_advance, line_gap: height, }; @@ -361,13 +364,13 @@ impl FontHandleMethods for FontHandle { } } - fn identifier(&self) -> Atom { - self.font_data.identifier.clone() + fn identifier(&self) -> &FontIdentifier { + &self.font_data.identifier } } impl<'a> FontHandle { - fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), ()> { + fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), &'static str> { let char_size = pt_size.to_f64_px() * 64.0 + 0.5; unsafe { @@ -375,7 +378,7 @@ impl<'a> FontHandle { if succeeded(result) { Ok(()) } else { - Err(()) + Err("FT_Set_Char_Size failed") } } } @@ -392,6 +395,7 @@ impl<'a> FontHandle { } } + #[allow(clippy::mut_from_ref)] // Intended for this function fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec { unsafe { &mut (*self.face) } } @@ -402,10 +406,10 @@ impl<'a> FontHandle { // face.size is a *c_void in the bindings, presumably to avoid // recursive structural types let size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) }; - let metrics: &FT_Size_Metrics = &(*size).metrics; + let metrics: &FT_Size_Metrics = &(size).metrics; let em_size = face.units_per_EM as f64; - let x_scale = (metrics.x_ppem as f64) / em_size as f64; + let x_scale = (metrics.x_ppem as f64) / em_size; // If this isn't true then we're scaling one of the axes wrong assert_eq!(metrics.x_ppem, metrics.y_ppem); diff --git a/components/gfx/platform/freetype/font_context.rs b/components/gfx/platform/freetype/font_context.rs index c5df0598563..b08ff552261 100644 --- a/components/gfx/platform/freetype/font_context.rs +++ b/components/gfx/platform/freetype/font_context.rs @@ -109,8 +109,8 @@ impl MallocSizeOf for FontContextHandle { } } -impl FontContextHandle { - pub fn new() -> FontContextHandle { +impl Default for FontContextHandle { + fn default() -> Self { let user = Box::into_raw(Box::new(User { size: 0 })); let mem = Box::into_raw(Box::new(FT_MemoryRec_ { user: user as *mut c_void, diff --git a/components/gfx/platform/freetype/font_list.rs b/components/gfx/platform/freetype/font_list.rs index a5363fc4848..4f17d0bd1b2 100644 --- a/components/gfx/platform/freetype/font_list.rs +++ b/components/gfx/platform/freetype/font_list.rs @@ -13,14 +13,25 @@ use fontconfig_sys::{ }; use libc::{c_char, c_int}; use log::debug; +use serde::{Deserialize, Serialize}; +use style::Atom; use super::c_str_to_string; use crate::text::util::is_cjk; -static FC_FAMILY: &'static [u8] = b"family\0"; -static FC_FILE: &'static [u8] = b"file\0"; -static FC_INDEX: &'static [u8] = b"index\0"; -static FC_FONTFORMAT: &'static [u8] = b"fontformat\0"; +static FC_FAMILY: &[u8] = b"family\0"; +static FC_FILE: &[u8] = b"file\0"; +static FC_INDEX: &[u8] = b"index\0"; +static FC_FONTFORMAT: &[u8] = b"fontformat\0"; + +/// An identifier for a local font on systems using Freetype. +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct LocalFontIdentifier { + /// The path to the font. + pub path: Atom, + /// The variation index within the font. + pub variation_index: i32, +} pub fn for_each_available_family(mut callback: F) where @@ -59,7 +70,7 @@ where pub fn for_each_variation(family_name: &str, mut callback: F) where - F: FnMut(String), + F: FnMut(LocalFontIdentifier), { debug!("getting variations for {}", family_name); unsafe { @@ -84,31 +95,24 @@ where FcObjectSetAdd(object_set, FC_INDEX.as_ptr() as *mut c_char); let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set); - debug!("found {} variations", (*matches).nfont); for i in 0..((*matches).nfont as isize) { let font = (*matches).fonts.offset(i); - let mut file: *mut FcChar8 = ptr::null_mut(); - let result = FcPatternGetString(*font, FC_FILE.as_ptr() as *mut c_char, 0, &mut file); - let file = if result == FcResultMatch { - c_str_to_string(file as *const c_char) - } else { - panic!(); - }; + + let mut path: *mut FcChar8 = ptr::null_mut(); + let result = FcPatternGetString(*font, FC_FILE.as_ptr() as *mut c_char, 0, &mut path); + assert_eq!(result, FcResultMatch); + let mut index: libc::c_int = 0; let result = FcPatternGetInteger(*font, FC_INDEX.as_ptr() as *mut c_char, 0, &mut index); - let index = if result == FcResultMatch { - index - } else { - panic!(); - }; + assert_eq!(result, FcResultMatch); - debug!("variation file: {}", file); - debug!("variation index: {}", index); - - callback(file); + callback(LocalFontIdentifier { + path: Atom::from(c_str_to_string(path as *const c_char)), + variation_index: index as i32, + }); } FcFontSetDestroy(matches); @@ -150,7 +154,7 @@ pub fn system_default_family(generic_name: &str) -> Option { } } -pub static SANS_SERIF_FONT_FAMILY: &'static str = "DejaVu Sans"; +pub static SANS_SERIF_FONT_FAMILY: &str = "DejaVu Sans"; // Based on gfxPlatformGtk::GetCommonFallbackFonts() in Gecko pub fn fallback_font_families(codepoint: Option) -> Vec<&'static str> { @@ -162,6 +166,16 @@ pub fn fallback_font_families(codepoint: Option) -> Vec<&'static str> { families.push("Droid Sans Fallback"); families.push("WenQuanYi Micro Hei"); families.push("NanumGothic"); + families.push("Noto Sans CJK HK"); + families.push("Noto Sans CJK JP"); + families.push("Noto Sans CJK KR"); + families.push("Noto Sans CJK SC"); + families.push("Noto Sans CJK TC"); + families.push("Noto Sans HK"); + families.push("Noto Sans JP"); + families.push("Noto Sans KR"); + families.push("Noto Sans SC"); + families.push("Noto Sans TC"); } } diff --git a/components/gfx/platform/freetype/font_template.rs b/components/gfx/platform/freetype/font_template.rs index cb3a1ef3857..b9896e15ea8 100644 --- a/components/gfx/platform/freetype/font_template.rs +++ b/components/gfx/platform/freetype/font_template.rs @@ -5,70 +5,89 @@ use std::fmt; use std::fs::File; use std::io::{Error, Read}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; use serde::{Deserialize, Serialize}; -use servo_atoms::Atom; use webrender_api::NativeFontHandle; +use crate::font_cache_thread::FontIdentifier; + /// Platform specific font representation for Linux. -/// The identifier is an absolute path, and the bytes -/// field is the loaded data that can be passed to -/// freetype and Raqote directly. #[derive(Deserialize, Serialize)] pub struct FontTemplateData { - // If you add members here, review the Debug impl below - pub bytes: Option>, - pub identifier: Atom, + /// Lazily-loaded (for local fonts) byte data that can be passed + /// to Freetype or Raqote directly. + pub font_data: RwLock>>>, + pub identifier: FontIdentifier, } impl fmt::Debug for FontTemplateData { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("FontTemplateData") - .field( - "bytes", - &self.bytes.as_ref().map(|b| format!("[{} bytes]", b.len())), - ) .field("identifier", &self.identifier) + .field( + "font_data", + &self + .font_data + .read() + .unwrap() + .as_ref() + .map(|bytes| format!("[{} bytes]", bytes.len())), + ) .finish() } } impl FontTemplateData { - pub fn new(identifier: Atom, bytes: Option>) -> Result { + pub fn new( + identifier: FontIdentifier, + font_data: Option>, + ) -> Result { Ok(FontTemplateData { - bytes: bytes, - identifier: identifier, + identifier, + font_data: RwLock::new(font_data.map(Arc::new)), }) } - /// Returns a clone of the data in this font. This may be a hugely expensive + /// Returns a reference to the data in this font. This may be a hugely expensive /// operation (depending on the platform) which performs synchronous disk I/O /// and should never be done lightly. - pub fn bytes(&self) -> Vec { - self.bytes_if_in_memory().unwrap_or_else(|| { - let mut file = File::open(&*self.identifier).expect("Couldn't open font file!"); - let mut buffer = vec![]; - file.read_to_end(&mut buffer).unwrap(); - buffer - }) + pub fn bytes(&self) -> Arc> { + self.font_data + .write() + .unwrap() + .get_or_insert_with(|| { + let path = match &self.identifier { + FontIdentifier::Local(local) => local.path.clone(), + FontIdentifier::Web(_) => unreachable!("Web fonts should always have data."), + }; + let mut bytes = Vec::new(); + File::open(Path::new(&*path)) + .expect("Couldn't open font file!") + .read_to_end(&mut bytes) + .unwrap(); + Arc::new(bytes) + }) + .clone() } - /// Returns a clone of the bytes in this font if they are in memory. This function never - /// performs disk I/O. - pub fn bytes_if_in_memory(&self) -> Option> { - self.bytes.clone() + /// Returns a reference to the bytes in this font if they are in memory. This function + /// never performs disk I/O. + pub fn bytes_if_in_memory(&self) -> Option>> { + self.font_data.read().unwrap().as_ref().cloned() } /// Returns the native font that underlies this font template, if applicable. pub fn native_font(&self) -> Option { - if self.bytes.is_none() { - Some(NativeFontHandle { - path: PathBuf::from(&*self.identifier), - index: 0, - }) - } else { - None - } + let local_identifier = match &self.identifier { + FontIdentifier::Local(local_identifier) => local_identifier, + FontIdentifier::Web(_) => return None, + }; + + Some(NativeFontHandle { + path: PathBuf::from(&*local_identifier.path), + index: 0, + }) } } diff --git a/components/gfx/platform/macos/font.rs b/components/gfx/platform/macos/font.rs index 552004d98ed..764519f8632 100644 --- a/components/gfx/platform/macos/font.rs +++ b/components/gfx/platform/macos/font.rs @@ -2,6 +2,7 @@ * 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::cmp::Ordering; use std::ops::Range; use std::sync::Arc; use std::{fmt, ptr}; @@ -19,13 +20,13 @@ use core_text::font_descriptor::{ kCTFontDefaultOrientation, SymbolicTraitAccessors, TraitAccessors, }; use log::debug; -use servo_atoms::Atom; use style::values::computed::font::{FontStretch, FontStyle, FontWeight}; use crate::font::{ FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, GPOS, GSUB, KERN, }; +use crate::font_cache_thread::FontIdentifier; use crate::platform::font_template::FontTemplateData; use crate::platform::macos::font_context::FontContextHandle; use crate::text::glyph::GlyphId; @@ -52,7 +53,7 @@ fn au_from_pt(pt: f64) -> Au { impl FontTable { pub fn wrap(data: CFData) -> FontTable { - FontTable { data: data } + FontTable { data } } } @@ -76,7 +77,7 @@ impl FontHandle { fn find_h_kern_subtable(&self) -> Option { let font_table = self.table_for_tag(KERN)?; let mut result = CachedKernTable { - font_table: font_table, + font_table, pair_data_range: 0..0, px_per_font_unit: 0.0, }; @@ -101,7 +102,7 @@ impl FontHandle { let end = start + len; if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 { // Found a matching subtable. - if result.pair_data_range.len() > 0 { + if !result.pair_data_range.is_empty() { debug!("Found multiple horizontal kern tables. Disable fast path."); return None; } @@ -117,13 +118,13 @@ impl FontHandle { } let pt_per_font_unit = - self.ctfont.pt_size() as f64 / self.ctfont.units_per_em() as f64; + self.ctfont.pt_size() / self.ctfont.units_per_em() as f64; result.px_per_font_unit = pt_to_px(pt_per_font_unit); } start = end; } } - if result.pair_data_range.len() > 0 { + if !result.pair_data_range.is_empty() { Some(result) } else { None @@ -147,12 +148,12 @@ impl CachedKernTable { while start < end { let i = (start + end) / 2; let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]); - if key > query { - end = i; - } else if key < query { - start = i + 1; - } else { - return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..])); + match key.cmp(&query) { + Ordering::Less => start = i + 1, + Ordering::Equal => { + return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..])) + }, + Ordering::Greater => end = i, } } None @@ -170,7 +171,7 @@ impl FontHandleMethods for FontHandle { _fctx: &FontContextHandle, template: Arc, pt_size: Option, - ) -> Result { + ) -> Result { let size = match pt_size { Some(s) => s.to_f64_px(), None => 0.0, @@ -190,7 +191,7 @@ impl FontHandleMethods for FontHandle { handle.table_for_tag(GSUB).is_none(); Ok(handle) }, - None => Err(()), + None => Err("Could not generate CTFont for FontTemplateData"), } } @@ -247,7 +248,7 @@ impl FontHandleMethods for FontHandle { return None; } - return Some(glyphs[0] as GlyphId); + Some(glyphs[0] as GlyphId) } fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel { @@ -278,43 +279,43 @@ impl FontHandleMethods for FontHandle { fn metrics(&self) -> FontMetrics { let bounding_rect: CGRect = self.ctfont.bounding_box(); - let ascent = self.ctfont.ascent() as f64; - let descent = self.ctfont.descent() as f64; - let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64); - let leading = self.ctfont.leading() as f64; + let ascent = self.ctfont.ascent(); + let descent = self.ctfont.descent(); + let em_size = Au::from_f64_px(self.ctfont.pt_size()); + let leading = self.ctfont.leading(); - let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent); + let scale = px_to_pt(self.ctfont.pt_size()) / (ascent + descent); let line_gap = (ascent + descent + leading + 0.5).floor(); - let max_advance_width = au_from_pt(bounding_rect.size.width as f64); + let max_advance = au_from_pt(bounding_rect.size.width); let average_advance = self .glyph_index('0') .and_then(|idx| self.glyph_h_advance(idx)) .map(Au::from_f64_px) - .unwrap_or(max_advance_width); + .unwrap_or(max_advance); let metrics = FontMetrics { - underline_size: au_from_pt(self.ctfont.underline_thickness() as f64), + underline_size: au_from_pt(self.ctfont.underline_thickness()), // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table // directly. // // see also: https://bugs.webkit.org/show_bug.cgi?id=16768 // see also: https://bugreports.qt-project.org/browse/QTBUG-13364 - underline_offset: au_from_pt(self.ctfont.underline_position() as f64), + underline_offset: au_from_pt(self.ctfont.underline_position()), strikeout_size: Au(0), // FIXME(Issue #942) strikeout_offset: Au(0), // FIXME(Issue #942) leading: au_from_pt(leading), - x_height: au_from_pt((self.ctfont.x_height() as f64) * scale), - em_size: em_size, + x_height: au_from_pt(self.ctfont.x_height() * scale), + em_size, ascent: au_from_pt(ascent * scale), descent: au_from_pt(descent * scale), - max_advance: max_advance_width, - average_advance: average_advance, + max_advance, + average_advance, line_gap: Au::from_f64_px(line_gap), }; debug!( "Font metrics (@{} pt): {:?}", - self.ctfont.pt_size() as f64, + self.ctfont.pt_size(), metrics ); metrics @@ -322,10 +323,10 @@ impl FontHandleMethods for FontHandle { fn table_for_tag(&self, tag: FontTableTag) -> Option { let result: Option = self.ctfont.get_font_table(tag); - result.and_then(|data| Some(FontTable::wrap(data))) + result.map(FontTable::wrap) } - fn identifier(&self) -> Atom { - self.font_data.identifier.clone() + fn identifier(&self) -> &FontIdentifier { + &self.font_data.identifier } } diff --git a/components/gfx/platform/macos/font_context.rs b/components/gfx/platform/macos/font_context.rs index 753cb97a572..b296ce6738b 100644 --- a/components/gfx/platform/macos/font_context.rs +++ b/components/gfx/platform/macos/font_context.rs @@ -4,16 +4,10 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct FontContextHandle { - _ctx: (), -} - -impl FontContextHandle { // this is a placeholder until NSFontManager or whatever is bound in here. - pub fn new() -> FontContextHandle { - FontContextHandle { _ctx: () } - } + _ctx: (), } impl MallocSizeOf for FontContextHandle { diff --git a/components/gfx/platform/macos/font_list.rs b/components/gfx/platform/macos/font_list.rs index 32b8b93b21f..14f9f1fa34a 100644 --- a/components/gfx/platform/macos/font_list.rs +++ b/components/gfx/platform/macos/font_list.rs @@ -3,10 +3,21 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use log::debug; +use serde::{Deserialize, Serialize}; +use style::Atom; use ucd::{Codepoint, UnicodeBlock}; use crate::text::util::unicode_plane; +/// An identifier for a local font on a MacOS system. These values comes from the CoreText +/// CTFontCollection. Note that `path` here is required. We do not load fonts that do not +/// have paths. +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct LocalFontIdentifier { + pub postscript_name: Atom, + pub path: Atom, +} + pub fn for_each_available_family(mut callback: F) where F: FnMut(String), @@ -19,7 +30,7 @@ where pub fn for_each_variation(family_name: &str, mut callback: F) where - F: FnMut(String), + F: FnMut(LocalFontIdentifier), { debug!("Looking for faces of family: {}", family_name); @@ -27,7 +38,15 @@ where if let Some(family_collection) = family_collection { if let Some(family_descriptors) = family_collection.get_descriptors() { for family_descriptor in family_descriptors.iter() { - callback(family_descriptor.font_name()); + let path = family_descriptor.font_path(); + let path = match path.as_ref().and_then(|path| path.to_str()) { + Some(path) => path, + None => continue, + }; + callback(LocalFontIdentifier { + postscript_name: Atom::from(family_descriptor.font_name()), + path: Atom::from(path), + }) } } } @@ -194,4 +213,4 @@ pub fn fallback_font_families(codepoint: Option) -> Vec<&'static str> { families } -pub static SANS_SERIF_FONT_FAMILY: &'static str = "Helvetica"; +pub static SANS_SERIF_FONT_FAMILY: &str = "Helvetica"; diff --git a/components/gfx/platform/macos/font_template.rs b/components/gfx/platform/macos/font_template.rs index 9e3c4a72f1b..8320a358622 100644 --- a/components/gfx/platform/macos/font_template.rs +++ b/components/gfx/platform/macos/font_template.rs @@ -2,34 +2,27 @@ * 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::borrow::ToOwned; +use std::collections::hash_map::Entry; use std::collections::HashMap; use std::fmt; -use std::fs::{self, File}; +use std::fs::File; use std::io::{Error as IoError, Read}; use std::ops::Deref; use std::path::Path; use std::sync::{Arc, Mutex, RwLock}; use app_units::Au; -use core_foundation::array::CFArray; -use core_foundation::base::{CFType, TCFType}; -use core_foundation::dictionary::CFDictionary; -use core_foundation::string::CFString; use core_graphics::data_provider::CGDataProvider; use core_graphics::font::CGFont; use core_text::font::CTFont; -use core_text::{font_collection, font_descriptor}; use serde::de::{Error, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use servo_atoms::Atom; -use servo_url::ServoUrl; use webrender_api::NativeFontHandle; -/// Platform specific font representation for mac. -/// The identifier is a PostScript font name. The -/// CTFont object is cached here for use by the -/// paint functions that create CGFont references. +use crate::font_cache_thread::FontIdentifier; + +/// Platform specific font representation for MacOS. CTFont object is cached here for use +/// by the paint functions that create CGFont references. #[derive(Deserialize, Serialize)] pub struct FontTemplateData { // If you add members here, review the Debug impl below @@ -41,8 +34,7 @@ pub struct FontTemplateData { /// the other side, because `CTFont` instances cannot be sent across processes. This is /// harmless, however, because it can always be recreated. ctfont: CachedCTFont, - - pub identifier: Atom, + pub identifier: FontIdentifier, pub font_data: RwLock>>>, } @@ -68,10 +60,13 @@ unsafe impl Send for FontTemplateData {} unsafe impl Sync for FontTemplateData {} impl FontTemplateData { - pub fn new(identifier: Atom, font_data: Option>) -> Result { + pub fn new( + identifier: FontIdentifier, + font_data: Option>, + ) -> Result { Ok(FontTemplateData { ctfont: CachedCTFont(Mutex::new(HashMap::new())), - identifier: identifier.to_owned(), + identifier, font_data: RwLock::new(font_data.map(Arc::new)), }) } @@ -79,111 +74,65 @@ impl FontTemplateData { /// Retrieves the Core Text font instance, instantiating it if necessary. pub fn ctfont(&self, pt_size: f64) -> Option { let mut ctfonts = self.ctfont.lock().unwrap(); - let pt_size_key = Au::from_f64_px(pt_size); - if !ctfonts.contains_key(&pt_size_key) { - // If you pass a zero font size to one of the Core Text APIs, it'll replace it with - // 12.0. We don't want that! (Issue #10492.) - let clamped_pt_size = pt_size.max(0.01); - let mut font_data = self.font_data.write().unwrap(); - let ctfont = match *font_data { - Some(ref bytes) => { - let fontprov = CGDataProvider::from_buffer(bytes.clone()); - let cgfont_result = CGFont::from_data_provider(fontprov); - match cgfont_result { - Ok(cgfont) => { - Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size)) - }, - Err(_) => None, - } - }, - None => { - // We can't rely on Core Text to load a font for us by postscript - // name here, due to https://github.com/servo/servo/issues/23290. - // The APIs will randomly load the wrong font, forcing us to use - // the roundabout route of creating a Core Graphics font from a - // a set of descriptors and then creating a Core Text font from - // that one. - let attributes: CFDictionary = - CFDictionary::from_CFType_pairs(&[( - CFString::new("NSFontNameAttribute"), - CFString::new(&*self.identifier).as_CFType(), - )]); - - let descriptor = font_descriptor::new_from_attributes(&attributes); - let descriptors = CFArray::from_CFTypes(&[descriptor]); - let collection = font_collection::new_from_descriptors(&descriptors); - collection.get_descriptors().and_then(|descriptors| { - let descriptor = descriptors.get(0).unwrap(); - let font_path = Path::new(&descriptor.font_path().unwrap()).to_owned(); - fs::read(&font_path).ok().and_then(|bytes| { - let font_bytes = Arc::new(bytes); - let fontprov = CGDataProvider::from_buffer(font_bytes.clone()); - CGFont::from_data_provider(fontprov).ok().map(|cgfont| { - *font_data = Some(font_bytes); - core_text::font::new_from_CGFont(&cgfont, clamped_pt_size) - }) - }) - }) - }, - }; - if let Some(ctfont) = ctfont { - ctfonts.insert(pt_size_key, ctfont); - } + let entry = ctfonts.entry(Au::from_f64_px(pt_size)); + match entry { + Entry::Occupied(entry) => return Some(entry.get().clone()), + Entry::Vacant(_) => {}, } - ctfonts.get(&pt_size_key).map(|ctfont| (*ctfont).clone()) + + // If you pass a zero font size to one of the Core Text APIs, it'll replace it with + // 12.0. We don't want that! (Issue #10492.) + let clamped_pt_size = pt_size.max(0.01); + + let provider = CGDataProvider::from_buffer(self.bytes()); + let cgfont = CGFont::from_data_provider(provider).ok()?; + let ctfont = core_text::font::new_from_CGFont(&cgfont, clamped_pt_size); + + // Cache the newly created CTFont font. + entry.or_insert(ctfont.clone()); + + Some(ctfont) } - /// Returns a clone of the data in this font. This may be a hugely expensive + /// Returns a reference to the data in this font. This may be a hugely expensive /// operation (depending on the platform) which performs synchronous disk I/O /// and should never be done lightly. - pub fn bytes(&self) -> Vec { - if let Some(font_data) = self.bytes_if_in_memory() { - return font_data; - } - - // This is spooky action at a distance, but getting a CTFont from this template - // will (in the common case) bring the bytes into memory if they were not there - // already. This also helps work around intermittent panics like - // https://github.com/servo/servo/issues/24622 that occur for unclear reasons. - let ctfont = self.ctfont(0.0); - if let Some(font_data) = self.bytes_if_in_memory() { - return font_data; - } - - let path = ServoUrl::parse( - &*ctfont - .expect("No Core Text font available!") - .url() - .expect("No URL for Core Text font!") - .get_string() - .to_string(), - ) - .expect("Couldn't parse Core Text font URL!") - .to_file_path() - .expect("Core Text font didn't name a path!"); - let mut bytes = Vec::new(); - File::open(path) - .expect("Couldn't open font file!") - .read_to_end(&mut bytes) - .unwrap(); - bytes + pub fn bytes(&self) -> Arc> { + self.font_data + .write() + .unwrap() + .get_or_insert_with(|| { + let path = match &self.identifier { + FontIdentifier::Local(local) => local.path.clone(), + FontIdentifier::Web(_) => unreachable!("Web fonts should always have data."), + }; + let mut bytes = Vec::new(); + File::open(Path::new(&*path)) + .expect("Couldn't open font file!") + .read_to_end(&mut bytes) + .unwrap(); + Arc::new(bytes) + }) + .clone() } - /// Returns a clone of the bytes in this font if they are in memory. This function never - /// performs disk I/O. - pub fn bytes_if_in_memory(&self) -> Option> { - self.font_data - .read() - .unwrap() - .as_ref() - .map(|bytes| (**bytes).clone()) + /// Returns a reference to the bytes in this font if they are in memory. + /// This function never performs disk I/O. + pub fn bytes_if_in_memory(&self) -> Option>> { + self.font_data.read().unwrap().as_ref().cloned() } /// Returns the native font that underlies this font template, if applicable. pub fn native_font(&self) -> Option { - self.ctfont(0.0) - .map(|ctfont| NativeFontHandle(ctfont.copy_to_CGFont())) + let local_identifier = match &self.identifier { + FontIdentifier::Local(local_identifier) => local_identifier, + FontIdentifier::Web(_) => return None, + }; + Some(NativeFontHandle { + name: local_identifier.postscript_name.to_string(), + path: local_identifier.path.to_string(), + }) } } diff --git a/components/gfx/platform/windows/font.rs b/components/gfx/platform/windows/font.rs index 4e57d00c187..73d6687ffc8 100644 --- a/components/gfx/platform/windows/font.rs +++ b/components/gfx/platform/windows/font.rs @@ -13,7 +13,6 @@ use std::sync::Arc; use app_units::Au; use dwrote::{Font, FontFace, FontFile, FontStretch, FontStyle}; use log::debug; -use servo_atoms::Atom; use style::computed_values::font_stretch::T as StyleFontStretch; use style::computed_values::font_weight::T as StyleFontWeight; use style::values::computed::font::FontStyle as StyleFontStyle; @@ -22,9 +21,9 @@ use style::values::specified::font::FontStretchKeyword; use crate::font::{ FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, }; +use crate::font_cache_thread::FontIdentifier; use crate::platform::font_template::FontTemplateData; use crate::platform::windows::font_context::FontContextHandle; -use crate::platform::windows::font_list::font_from_atom; use crate::text::glyph::GlyphId; // 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch @@ -64,8 +63,6 @@ fn make_tag(tag_bytes: &[u8]) -> FontTableTag { unsafe { *(tag_bytes.as_ptr() as *const FontTableTag) } } -macro_rules! try_lossy(($result:expr) => ($result.map_err(|_| (()))?)); - // We need the font (DWriteFont) in order to be able to query things like // the family name, face name, weight, etc. On Windows 10, the // DWriteFontFace3 interface provides this on the FontFace, but that's only @@ -84,7 +81,7 @@ struct FontInfo { } impl FontInfo { - fn new_from_face(face: &FontFace) -> Result { + fn new_from_face(face: &FontFace) -> Result { use std::cmp::{max, min}; use std::collections::HashMap; use std::io::Cursor; @@ -96,11 +93,11 @@ impl FontInfo { let names_bytes = face.get_font_table(make_tag(b"name")); let windows_metrics_bytes = face.get_font_table(make_tag(b"OS/2")); if names_bytes.is_none() || windows_metrics_bytes.is_none() { - return Err(()); + return Err("No 'name' or 'OS/2' tables"); } let mut cursor = Cursor::new(names_bytes.as_ref().unwrap()); - let table = try_lossy!(Names::read(&mut cursor)); + let table = Names::read(&mut cursor).map_err(|_| "Could not read 'name' table")?; let language_tags = table.language_tags().collect::>(); let mut names = table .iter() @@ -114,15 +111,15 @@ impl FontInfo { .collect::>(); let family = match names.remove(&NameID::FontFamilyName) { Some(family) => family, - _ => return Err(()), + _ => return Err("Could not find family"), }; let face = match names.remove(&NameID::FontSubfamilyName) { Some(face) => face, - _ => return Err(()), + _ => return Err("Could not find subfamily"), }; let mut cursor = Cursor::new(windows_metrics_bytes.as_ref().unwrap()); - let table = try_lossy!(WindowsMetrics::read(&mut cursor)); + let table = WindowsMetrics::read(&mut cursor).map_err(|_| "Could not read OS/2 table")?; let (weight_val, width_val, italic_bool) = match table { WindowsMetrics::Version0(ref m) => { (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1) @@ -152,7 +149,7 @@ impl FontInfo { 7 => FontStretchKeyword::Expanded, 8 => FontStretchKeyword::ExtraExpanded, 9 => FontStretchKeyword::UltraExpanded, - _ => return Err(()), + _ => return Err("Unknown stretch size"), } .compute(); @@ -171,7 +168,7 @@ impl FontInfo { }) } - fn new_from_font(font: &Font) -> Result { + fn new_from_font(font: &Font) -> Result { let style = match font.style() { FontStyle::Normal => StyleFontStyle::NORMAL, FontStyle::Oblique => StyleFontStyle::OBLIQUE, @@ -208,7 +205,6 @@ pub struct FontHandle { face: Nondebug, info: FontInfo, em_size: f32, - du_per_em: f32, du_to_px: f32, scaled_du_to_px: f32, } @@ -235,25 +231,19 @@ impl FontHandleMethods for FontHandle { _: &FontContextHandle, template: Arc, pt_size: Option, - ) -> Result { - let (info, face) = if let Some(ref raw_font) = template.bytes { - let font_file = FontFile::new_from_data(Arc::new(raw_font.clone())); - if font_file.is_none() { - // failed to load raw font - return Err(()); - } - - let face = font_file - .unwrap() - .create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE) - .map_err(|_| ())?; - let info = FontInfo::new_from_face(&face)?; - (info, face) - } else { - let font = font_from_atom(&template.identifier); - let face = font.create_font_face(); - let info = FontInfo::new_from_font(&font)?; - (info, face) + ) -> Result { + let (face, info) = match template.get_font() { + Some(font) => (font.create_font_face(), FontInfo::new_from_font(&font)?), + None => { + let bytes = template.bytes(); + let font_file = + FontFile::new_from_data(bytes).ok_or_else(|| "Could not create FontFile")?; + let face = font_file + .create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE) + .map_err(|_| "Could not create FontFace")?; + let info = FontInfo::new_from_face(&face)?; + (face, info) + }, }; let pt_size = pt_size.unwrap_or(au_from_pt(12.)); @@ -268,9 +258,8 @@ impl FontHandleMethods for FontHandle { Ok(FontHandle { font_data: template.clone(), face: Nondebug(face), - info: info, - em_size: em_size, - du_per_em: du_per_em, + info, + em_size, du_to_px: design_units_to_pixels, scaled_du_to_px: scaled_design_units_to_pixels, }) @@ -366,7 +355,7 @@ impl FontHandleMethods for FontHandle { .map(|bytes| FontTable { data: bytes }) } - fn identifier(&self) -> Atom { - self.font_data.identifier.clone() + fn identifier(&self) -> &FontIdentifier { + &self.font_data.identifier } } diff --git a/components/gfx/platform/windows/font_context.rs b/components/gfx/platform/windows/font_context.rs index d5e0015dd56..a67a366fc11 100644 --- a/components/gfx/platform/windows/font_context.rs +++ b/components/gfx/platform/windows/font_context.rs @@ -4,14 +4,7 @@ use malloc_size_of::malloc_size_of_is_0; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct FontContextHandle; -impl FontContextHandle { - // *shrug* - pub fn new() -> FontContextHandle { - FontContextHandle {} - } -} - malloc_size_of_is_0!(FontContextHandle); diff --git a/components/gfx/platform/windows/font_list.rs b/components/gfx/platform/windows/font_list.rs index bf9c019cf97..bc5e0030972 100644 --- a/components/gfx/platform/windows/font_list.rs +++ b/components/gfx/platform/windows/font_list.rs @@ -2,23 +2,16 @@ * 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::collections::HashMap; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; +use std::hash::Hash; +use std::sync::Arc; -use dwrote::{Font, FontCollection, FontDescriptor}; -use lazy_static::lazy_static; -use servo_atoms::Atom; +use dwrote::{FontCollection, FontDescriptor}; +use serde::{Deserialize, Serialize}; use ucd::{Codepoint, UnicodeBlock}; use crate::text::util::unicode_plane; -lazy_static! { - static ref FONT_ATOM_COUNTER: AtomicUsize = AtomicUsize::new(1); - static ref FONT_ATOM_MAP: Mutex> = Mutex::new(HashMap::new()); -} - -pub static SANS_SERIF_FONT_FAMILY: &'static str = "Arial"; +pub static SANS_SERIF_FONT_FAMILY: &str = "Arial"; pub fn system_default_family(_: &str) -> Option { Some("Verdana".to_owned()) @@ -34,6 +27,24 @@ where } } +/// An identifier for a local font on a Windows system. +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct LocalFontIdentifier { + /// The FontDescriptor of this font. + pub font_descriptor: Arc, +} + +impl Eq for LocalFontIdentifier {} + +impl Hash for LocalFontIdentifier { + fn hash(&self, state: &mut H) { + self.font_descriptor.family_name.hash(state); + self.font_descriptor.weight.to_u32().hash(state); + self.font_descriptor.stretch.to_u32().hash(state); + self.font_descriptor.style.to_u32().hash(state); + } +} + // for_each_variation is supposed to return a string that can be // atomized and then uniquely used to return back to this font. // Some platforms use the full postscript name (MacOS X), or @@ -45,35 +56,20 @@ where pub fn for_each_variation(family_name: &str, mut callback: F) where - F: FnMut(String), + F: FnMut(LocalFontIdentifier), { let system_fc = FontCollection::system(); if let Some(family) = system_fc.get_font_family_by_name(family_name) { let count = family.get_font_count(); for i in 0..count { let font = family.get_font(i); - let index = FONT_ATOM_COUNTER.fetch_add(1, Ordering::Relaxed); - let index_str = format!("{}", index); - let atom = Atom::from(index_str.clone()); - - { - let descriptor = font.to_descriptor(); - let mut fonts = FONT_ATOM_MAP.lock().unwrap(); - fonts.insert(atom, descriptor); - } - - callback(index_str); + callback(LocalFontIdentifier { + font_descriptor: Arc::new(font.to_descriptor()), + }); } } } -pub fn font_from_atom(ident: &Atom) -> Font { - let fonts = FONT_ATOM_MAP.lock().unwrap(); - FontCollection::system() - .get_font_from_descriptor(fonts.get(ident).unwrap()) - .unwrap() -} - // Based on gfxWindowsPlatform::GetCommonFallbackFonts() in Gecko pub fn fallback_font_families(codepoint: Option) -> Vec<&'static str> { let mut families = vec!["Arial"]; diff --git a/components/gfx/platform/windows/font_template.rs b/components/gfx/platform/windows/font_template.rs index 85477d36b36..5e2469550dc 100644 --- a/components/gfx/platform/windows/font_template.rs +++ b/components/gfx/platform/windows/font_template.rs @@ -2,28 +2,32 @@ * 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::sync::{Arc, RwLock}; use std::{fmt, io}; +use dwrote::{Font, FontCollection}; use serde::{Deserialize, Serialize}; -use servo_atoms::Atom; use webrender_api::NativeFontHandle; -use crate::platform::windows::font_list::font_from_atom; +use crate::font_cache_thread::FontIdentifier; #[derive(Deserialize, Serialize)] pub struct FontTemplateData { - // If you add members here, review the Debug impl below - pub bytes: Option>, - pub identifier: Atom, + /// The identifier for this font. + pub identifier: FontIdentifier, + /// The bytes of this font, lazily loaded if this is a local font. + pub font_data: RwLock>>>, } impl fmt::Debug for FontTemplateData { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("FontTemplateData") .field( - "bytes", + "font_data", &self - .bytes + .font_data + .read() + .unwrap() .as_ref() .map(|bytes| format!("[{} bytes]", bytes.len())), ) @@ -34,40 +38,61 @@ impl fmt::Debug for FontTemplateData { impl FontTemplateData { pub fn new( - identifier: Atom, + identifier: FontIdentifier, font_data: Option>, ) -> Result { Ok(FontTemplateData { - bytes: font_data, - identifier: identifier, + identifier, + font_data: RwLock::new(font_data.map(Arc::new)), }) } - pub fn bytes(&self) -> Vec { - if self.bytes.is_some() { - self.bytes.as_ref().unwrap().clone() - } else { - let font = font_from_atom(&self.identifier); - let face = font.create_font_face(); - let files = face.get_files(); - assert!(files.len() > 0); + /// Returns a reference to the data in this font. This may be a hugely expensive + /// operation (depending on the platform) which performs synchronous disk I/O + /// and should never be done lightly. + pub fn bytes(&self) -> Arc> { + self.font_data + .write() + .unwrap() + .get_or_insert_with(|| { + let font_descriptor = match &self.identifier { + FontIdentifier::Local(local_identifier) => { + local_identifier.font_descriptor.clone() + }, + FontIdentifier::Web(_) => unreachable!("Created a web font without data."), + }; - files[0].get_font_file_bytes() - } + let font = FontCollection::system() + .get_font_from_descriptor(&font_descriptor) + .unwrap(); + let face = font.create_font_face(); + let files = face.get_files(); + assert!(!files.is_empty()); + Arc::new(files[0].get_font_file_bytes()) + }) + .clone() } - pub fn bytes_if_in_memory(&self) -> Option> { - self.bytes.clone() + /// Returns a reference to the bytes in this font if they are in memory. + /// This function never performs disk I/O. + pub fn bytes_if_in_memory(&self) -> Option>> { + self.font_data.read().unwrap().as_ref().cloned() + } + + /// Get a [`FontFace`] for this font if it is a local font or return `None` if it's a + /// web font. + pub fn get_font(&self) -> Option { + let font_descriptor = match &self.identifier { + FontIdentifier::Local(local_identifier) => local_identifier.font_descriptor.clone(), + FontIdentifier::Web(_) => return None, + }; + + FontCollection::system().get_font_from_descriptor(&font_descriptor) } pub fn native_font(&self) -> Option { - if self.bytes.is_some() { - return None; - } - let font = font_from_atom(&self.identifier); - let face = font.create_font_face(); - let files = face.get_files(); - let path = files.iter().next()?.get_font_file_path()?; + let face = self.get_font()?.create_font_face(); + let path = face.get_files().first()?.get_font_file_path()?; Some(NativeFontHandle { path, index: face.get_index(), diff --git a/components/gfx/rendering_context.rs b/components/gfx/rendering_context.rs index 4e78ba9117c..3ea7cbe6ebc 100644 --- a/components/gfx/rendering_context.rs +++ b/components/gfx/rendering_context.rs @@ -30,8 +30,8 @@ struct RenderingContextData { impl Drop for RenderingContextData { fn drop(&mut self) { - let ref mut device = self.device.borrow_mut(); - let ref mut context = self.context.borrow_mut(); + let device = &mut self.device.borrow_mut(); + let context = &mut self.context.borrow_mut(); if let Some(ref swap_chain) = self.swap_chain { let _ = swap_chain.destroy(device, context); } @@ -45,7 +45,7 @@ impl RenderingContext { adapter: &Adapter, surface_type: SurfaceType, ) -> Result { - let mut device = connection.create_device(&adapter)?; + let mut device = connection.create_device(adapter)?; let flags = ContextAttributeFlags::ALPHA | ContextAttributeFlags::DEPTH | ContextAttributeFlags::STENCIL; @@ -90,27 +90,28 @@ impl RenderingContext { Ok(RenderingContext(Rc::new(data))) } - pub fn create_surface_texture( - &self, - surface: Surface, - ) -> Result { - let ref device = self.0.device.borrow(); - let ref mut context = self.0.context.borrow_mut(); - device.create_surface_texture(context, surface) + pub fn create_surface_texture(&self, surface: Surface) -> Result { + let device = &self.0.device.borrow(); + let context = &mut self.0.context.borrow_mut(); + device + .create_surface_texture(context, surface) + .map_err(|(error, _)| error) } pub fn destroy_surface_texture( &self, surface_texture: SurfaceTexture, - ) -> Result { - let ref device = self.0.device.borrow(); - let ref mut context = self.0.context.borrow_mut(); - device.destroy_surface_texture(context, surface_texture) + ) -> Result { + let device = &self.0.device.borrow(); + let context = &mut self.0.context.borrow_mut(); + device + .destroy_surface_texture(context, surface_texture) + .map_err(|(error, _)| error) } pub fn make_gl_context_current(&self) -> Result<(), Error> { - let ref device = self.0.device.borrow(); - let ref context = self.0.context.borrow(); + let device = &self.0.device.borrow(); + let context = &self.0.context.borrow(); device.make_context_current(context) } @@ -119,8 +120,8 @@ impl RenderingContext { } pub fn resize(&self, size: Size2D) -> Result<(), Error> { - let ref mut device = self.0.device.borrow_mut(); - let ref mut context = self.0.context.borrow_mut(); + let device = &mut self.0.device.borrow_mut(); + let context = &mut self.0.context.borrow_mut(); if let Some(swap_chain) = self.0.swap_chain.as_ref() { return swap_chain.resize(device, context, size); } @@ -135,8 +136,8 @@ impl RenderingContext { } pub fn present(&self) -> Result<(), Error> { - let ref mut device = self.0.device.borrow_mut(); - let ref mut context = self.0.context.borrow_mut(); + let device = &mut self.0.device.borrow_mut(); + let context = &mut self.0.context.borrow_mut(); if let Some(ref swap_chain) = self.0.swap_chain { return swap_chain.swap_buffers(device, context, PreserveBuffer::No); } @@ -153,8 +154,8 @@ impl RenderingContext { /// Invoke a closure with the surface associated with the current front buffer. /// This can be used to create a surfman::SurfaceTexture to blit elsewhere. pub fn with_front_buffer Surface>(&self, mut f: F) { - let ref mut device = self.0.device.borrow_mut(); - let ref mut context = self.0.context.borrow_mut(); + let device = &mut self.0.device.borrow_mut(); + let context = &mut self.0.context.borrow_mut(); let surface = device .unbind_surface_from_context(context) .unwrap() @@ -168,52 +169,52 @@ impl RenderingContext { } pub fn connection(&self) -> Connection { - let ref device = self.0.device.borrow(); + let device = &self.0.device.borrow(); device.connection() } pub fn adapter(&self) -> Adapter { - let ref device = self.0.device.borrow(); + let device = &self.0.device.borrow(); device.adapter() } pub fn native_context(&self) -> NativeContext { - let ref device = self.0.device.borrow(); - let ref context = self.0.context.borrow(); + let device = &self.0.device.borrow(); + let context = &self.0.context.borrow(); device.native_context(context) } pub fn native_device(&self) -> NativeDevice { - let ref device = self.0.device.borrow(); + let device = &self.0.device.borrow(); device.native_device() } pub fn context_attributes(&self) -> ContextAttributes { - let ref device = self.0.device.borrow(); - let ref context = self.0.context.borrow(); - let ref descriptor = device.context_descriptor(context); + let device = &self.0.device.borrow(); + let context = &self.0.context.borrow(); + let descriptor = &device.context_descriptor(context); device.context_descriptor_attributes(descriptor) } pub fn context_surface_info(&self) -> Result, Error> { - let ref device = self.0.device.borrow(); - let ref context = self.0.context.borrow(); + let device = &self.0.device.borrow(); + let context = &self.0.context.borrow(); device.context_surface_info(context) } pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo { - let ref device = self.0.device.borrow(); + let device = &self.0.device.borrow(); device.surface_info(surface) } pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 { - let ref device = self.0.device.borrow(); + let device = &self.0.device.borrow(); device.surface_texture_object(surface) } pub fn get_proc_address(&self, name: &str) -> *const c_void { - let ref device = self.0.device.borrow(); - let ref context = self.0.context.borrow(); + let device = &self.0.device.borrow(); + let context = &self.0.context.borrow(); device.get_proc_address(context, name) } @@ -221,7 +222,7 @@ impl RenderingContext { let device = self.0.device.borrow_mut(); let mut context = self.0.context.borrow_mut(); let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap(); - let _ = device.destroy_surface(&mut context, &mut surface)?; + device.destroy_surface(&mut context, &mut surface)?; Ok(()) } diff --git a/components/gfx/tests/font_context.rs b/components/gfx/tests/font_context.rs index 6ea58172c27..088d61b4d3f 100644 --- a/components/gfx/tests/font_context.rs +++ b/components/gfx/tests/font_context.rs @@ -13,17 +13,19 @@ use app_units::Au; use gfx::font::{ fallback_font_families, FontDescriptor, FontFamilyDescriptor, FontFamilyName, FontSearchScope, }; -use gfx::font_cache_thread::{FontTemplateInfo, FontTemplates}; +use gfx::font_cache_thread::{FontIdentifier, FontTemplateInfo, FontTemplates}; use gfx::font_context::{FontContext, FontContextHandle, FontSource}; use gfx::font_template::FontTemplateDescriptor; use servo_arc::Arc; use servo_atoms::Atom; +use servo_url::ServoUrl; use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps; use style::properties::style_structs::Font as FontStyleStruct; use style::values::computed::font::{ FamilyName, FontFamily, FontFamilyList, FontFamilyNameSyntax, FontSize, FontStretch, FontStyle, FontWeight, SingleFontFamily, }; +use style::values::computed::FontLanguageOverride; use webrender_api::{FontInstanceKey, FontKey, IdNamespace}; struct TestFontSource { @@ -34,14 +36,14 @@ struct TestFontSource { impl TestFontSource { fn new() -> TestFontSource { - let mut csstest_ascii = FontTemplates::new(); - Self::add_face(&mut csstest_ascii, "csstest-ascii", None); + let mut csstest_ascii = FontTemplates::default(); + Self::add_face(&mut csstest_ascii, "csstest-ascii"); - let mut csstest_basic = FontTemplates::new(); - Self::add_face(&mut csstest_basic, "csstest-basic-regular", None); + let mut csstest_basic = FontTemplates::default(); + Self::add_face(&mut csstest_basic, "csstest-basic-regular"); - let mut fallback = FontTemplates::new(); - Self::add_face(&mut fallback, "csstest-basic-regular", Some("fallback")); + let mut fallback = FontTemplates::default(); + Self::add_face(&mut fallback, "csstest-basic-regular"); let mut families = HashMap::new(); families.insert("CSSTest ASCII".to_owned(), csstest_ascii); @@ -49,22 +51,31 @@ impl TestFontSource { families.insert(fallback_font_families(None)[0].to_owned(), fallback); TestFontSource { - handle: FontContextHandle::new(), + handle: FontContextHandle::default(), families, find_font_count: Rc::new(Cell::new(0)), } } - fn add_face(family: &mut FontTemplates, name: &str, identifier: Option<&str>) { + fn identifier_for_font_name(name: &str) -> FontIdentifier { + let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"] + .iter() + .collect(); + path.push(format!("{}.ttf", name)); + FontIdentifier::Web(ServoUrl::from_file_path(path).unwrap()) + } + + fn add_face(family: &mut FontTemplates, name: &str) { let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"] .iter() .collect(); path.push(format!("{}.ttf", name)); let file = File::open(path).unwrap(); - let identifier = Atom::from(identifier.unwrap_or(name)); - - family.add_template(identifier, Some(file.bytes().map(|b| b.unwrap()).collect())) + family.add_template( + Self::identifier_for_font_name(name), + Some(file.bytes().map(|b| b.unwrap()).collect()), + ) } } @@ -100,6 +111,7 @@ fn style() -> FontStyleStruct { font_size: FontSize::medium(), font_stretch: FontStretch::hundred(), hash: 0, + font_language_override: FontLanguageOverride::normal(), }; style.compute_font_hash(); style @@ -163,7 +175,10 @@ fn test_font_group_find_by_codepoint() { .borrow_mut() .find_by_codepoint(&mut context, 'a') .unwrap(); - assert_eq!(&*font.borrow().identifier(), "csstest-ascii"); + assert_eq!( + *font.borrow().identifier(), + TestFontSource::identifier_for_font_name("csstest-ascii") + ); assert_eq!( count.get(), 1, @@ -174,7 +189,10 @@ fn test_font_group_find_by_codepoint() { .borrow_mut() .find_by_codepoint(&mut context, 'a') .unwrap(); - assert_eq!(&*font.borrow().identifier(), "csstest-ascii"); + assert_eq!( + *font.borrow().identifier(), + TestFontSource::identifier_for_font_name("csstest-ascii") + ); assert_eq!( count.get(), 1, @@ -185,7 +203,10 @@ fn test_font_group_find_by_codepoint() { .borrow_mut() .find_by_codepoint(&mut context, 'á') .unwrap(); - assert_eq!(&*font.borrow().identifier(), "csstest-basic-regular"); + assert_eq!( + *font.borrow().identifier(), + TestFontSource::identifier_for_font_name("csstest-basic-regular") + ); assert_eq!(count.get(), 2, "both fonts should now have been loaded"); } @@ -204,8 +225,8 @@ fn test_font_fallback() { .find_by_codepoint(&mut context, 'a') .unwrap(); assert_eq!( - &*font.borrow().identifier(), - "csstest-ascii", + *font.borrow().identifier(), + TestFontSource::identifier_for_font_name("csstest-ascii"), "a family in the group should be used if there is a matching glyph" ); @@ -214,8 +235,8 @@ fn test_font_fallback() { .find_by_codepoint(&mut context, 'á') .unwrap(); assert_eq!( - &*font.borrow().identifier(), - "fallback", + *font.borrow().identifier(), + TestFontSource::identifier_for_font_name("csstest-basic-regular"), "a fallback font should be used if there is no matching glyph in the group" ); } diff --git a/components/gfx/tests/font_template.rs b/components/gfx/tests/font_template.rs index eecaacbd695..1c8420bc45c 100644 --- a/components/gfx/tests/font_template.rs +++ b/components/gfx/tests/font_template.rs @@ -10,9 +10,10 @@ fn test_font_template_descriptor() { use std::io::prelude::*; use std::path::PathBuf; + use gfx::font_cache_thread::FontIdentifier; use gfx::font_context::FontContextHandle; use gfx::font_template::{FontTemplate, FontTemplateDescriptor}; - use servo_atoms::Atom; + use servo_url::ServoUrl; use style::values::computed::font::{FontStretch, FontStyle, FontWeight}; fn descriptor(filename: &str) -> FontTemplateDescriptor { @@ -27,15 +28,14 @@ fn test_font_template_descriptor() { .collect(); path.push(format!("{}.ttf", filename)); - let file = File::open(path).unwrap(); - + let file = File::open(path.clone()).unwrap(); let mut template = FontTemplate::new( - Atom::from(filename), + FontIdentifier::Web(ServoUrl::from_file_path(path).unwrap()), Some(file.bytes().map(|b| b.unwrap()).collect()), ) .unwrap(); - let context = FontContextHandle::new(); + let context = FontContextHandle::default(); template.descriptor(&context).unwrap() } diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 98dc39bc0e4..3b42af4b4d5 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -28,7 +28,7 @@ pub struct GlyphEntry { impl GlyphEntry { fn new(value: u32) -> GlyphEntry { - GlyphEntry { value: value } + GlyphEntry { value } } fn initial() -> GlyphEntry { @@ -40,7 +40,7 @@ impl GlyphEntry { assert!(is_simple_glyph_id(id)); assert!(is_simple_advance(advance)); - let id_mask = id as u32; + let id_mask = id; let Au(advance) = advance; let advance_mask = (advance as u32) << GLYPH_ADVANCE_SHIFT; @@ -89,7 +89,7 @@ const GLYPH_ID_MASK: u32 = 0x0000FFFF; const GLYPH_COUNT_MASK: u32 = 0x0000FFFF; fn is_simple_glyph_id(id: GlyphId) -> bool { - ((id as u32) & GLYPH_ID_MASK) == id + (id & GLYPH_ID_MASK) == id } fn is_simple_advance(advance: Au) -> bool { @@ -157,9 +157,9 @@ struct DetailedGlyph { impl DetailedGlyph { fn new(id: GlyphId, advance: Au, offset: Point2D) -> DetailedGlyph { DetailedGlyph { - id: id, - advance: advance, - offset: offset, + id, + advance, + offset, } } } @@ -172,18 +172,18 @@ struct DetailedGlyphRecord { detail_offset: usize, } -impl PartialOrd for DetailedGlyphRecord { - fn partial_cmp(&self, other: &DetailedGlyphRecord) -> Option { - self.entry_offset.partial_cmp(&other.entry_offset) - } -} - impl Ord for DetailedGlyphRecord { fn cmp(&self, other: &DetailedGlyphRecord) -> Ordering { self.entry_offset.cmp(&other.entry_offset) } } +impl PartialOrd for DetailedGlyphRecord { + fn partial_cmp(&self, other: &DetailedGlyphRecord) -> Option { + Some(self.cmp(other)) + } +} + // Manages the lookup table for detailed glyphs. Sorting is deferred // until a lookup is actually performed; this matches the expected // usage pattern of setting/appending all the detailed glyphs, and @@ -210,7 +210,7 @@ impl<'a> DetailedGlyphStore { fn add_detailed_glyphs_for_entry(&mut self, entry_offset: ByteIndex, glyphs: &[DetailedGlyph]) { let entry = DetailedGlyphRecord { - entry_offset: entry_offset, + entry_offset, detail_offset: self.detail_buffer.len(), }; @@ -245,7 +245,7 @@ impl<'a> DetailedGlyphStore { assert!(self.lookup_is_sorted); let key = DetailedGlyphRecord { - entry_offset: entry_offset, + entry_offset, detail_offset: 0, // unused }; @@ -268,7 +268,7 @@ impl<'a> DetailedGlyphStore { assert!(self.lookup_is_sorted); let key = DetailedGlyphRecord { - entry_offset: entry_offset, + entry_offset, detail_offset: 0, // unused }; @@ -329,11 +329,11 @@ impl GlyphData { ligature_start: bool, ) -> GlyphData { GlyphData { - id: id, - advance: advance, + id, + advance, offset: offset.unwrap_or(Point2D::zero()), - cluster_start: cluster_start, - ligature_start: ligature_start, + cluster_start, + ligature_start, } } } @@ -455,8 +455,8 @@ impl<'a> GlyphStore { total_advance: Au(0), total_word_separators: 0, has_detailed_glyphs: false, - is_whitespace: is_whitespace, - is_rtl: is_rtl, + is_whitespace, + is_rtl, } } @@ -482,15 +482,15 @@ impl<'a> GlyphStore { pub fn finalize_changes(&mut self) { self.detail_store.ensure_sorted(); - self.cache_total_advance_and_word_seperators() + self.cache_total_advance_and_word_separators() } #[inline(never)] - fn cache_total_advance_and_word_seperators(&mut self) { + fn cache_total_advance_and_word_separators(&mut self) { let mut total_advance = Au(0); let mut total_word_separators = 0; for glyph in self.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), self.len())) { - total_advance = total_advance + glyph.advance(); + total_advance += glyph.advance(); if glyph.char_is_word_separator() { total_word_separators += 1; } @@ -539,7 +539,7 @@ impl<'a> GlyphStore { pub fn add_glyphs_for_byte_index(&mut self, i: ByteIndex, data_for_glyphs: &[GlyphData]) { assert!(i < self.len()); - assert!(data_for_glyphs.len() > 0); + assert!(!data_for_glyphs.is_empty()); let glyph_count = data_for_glyphs.len(); @@ -623,8 +623,6 @@ impl<'a> GlyphStore { pub fn advance_for_byte_range(&self, range: &Range, extra_word_spacing: Au) -> Au { if range.begin() == ByteIndex(0) && range.end() == self.len() { self.total_advance + extra_word_spacing * (self.total_word_separators as i32) - } else if !self.has_detailed_glyphs { - self.advance_for_byte_range_simple_glyphs(range, extra_word_spacing) } else { self.advance_for_byte_range_simple_glyphs(range, extra_word_spacing) } @@ -664,13 +662,13 @@ impl<'a> GlyphStore { impl fmt::Debug for GlyphStore { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "GlyphStore:\n")?; + writeln!(formatter, "GlyphStore:")?; let mut detailed_buffer = self.detail_store.detail_buffer.iter(); for entry in self.entry_buffer.iter() { if entry.is_simple() { - write!( + writeln!( formatter, - " simple id={:?} advance={:?}\n", + " simple id={:?} advance={:?}", entry.id(), entry.advance() )?; @@ -683,9 +681,9 @@ impl fmt::Debug for GlyphStore { if detailed_buffer.next().is_none() { continue; } - write!( + writeln!( formatter, - " detailed id={:?} advance={:?}\n", + " detailed id={:?} advance={:?}", entry.id(), entry.advance() )?; diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs index 389a44b5457..74df4b5dccf 100644 --- a/components/gfx/text/shaping/harfbuzz.rs +++ b/components/gfx/text/shaping/harfbuzz.rs @@ -47,21 +47,24 @@ pub struct ShapedGlyphEntry { } impl ShapedGlyphData { - pub fn new(buffer: *mut hb_buffer_t) -> ShapedGlyphData { - unsafe { - let mut glyph_count = 0; - let glyph_infos = hb_buffer_get_glyph_infos(buffer, &mut glyph_count); - assert!(!glyph_infos.is_null()); - let mut pos_count = 0; - let pos_infos = hb_buffer_get_glyph_positions(buffer, &mut pos_count); - assert!(!pos_infos.is_null()); - assert_eq!(glyph_count, pos_count); + /// Create a new [`SharedGlyphData`] from the given HarfBuzz buffer. + /// + /// # Safety + /// + /// Passing an invalid buffer pointer to this function results in undefined behavior. + pub unsafe fn new(buffer: *mut hb_buffer_t) -> ShapedGlyphData { + let mut glyph_count = 0; + let glyph_infos = hb_buffer_get_glyph_infos(buffer, &mut glyph_count); + assert!(!glyph_infos.is_null()); + let mut pos_count = 0; + let pos_infos = hb_buffer_get_glyph_positions(buffer, &mut pos_count); + assert!(!pos_infos.is_null()); + assert_eq!(glyph_count, pos_count); - ShapedGlyphData { - count: glyph_count as usize, - glyph_infos: glyph_infos, - pos_infos: pos_infos, - } + ShapedGlyphData { + count: glyph_count as usize, + glyph_infos, + pos_infos, } } @@ -70,7 +73,7 @@ impl ShapedGlyphData { assert!(i < self.count); unsafe { - let glyph_info_i = self.glyph_infos.offset(i as isize); + let glyph_info_i = self.glyph_infos.add(i); (*glyph_info_i).cluster } } @@ -79,13 +82,17 @@ impl ShapedGlyphData { self.count } + pub fn is_empty(&self) -> bool { + self.count == 0 + } + /// Returns shaped glyph data for one glyph, and updates the y-position of the pen. pub fn entry_for_glyph(&self, i: usize, y_pos: &mut Au) -> ShapedGlyphEntry { assert!(i < self.count); unsafe { - let glyph_info_i = self.glyph_infos.offset(i as isize); - let pos_info_i = self.pos_infos.offset(i as isize); + let glyph_info_i = self.glyph_infos.add(i); + let pos_info_i = self.pos_infos.add(i); let x_offset = Shaper::fixed_to_float((*pos_info_i).x_offset); let y_offset = Shaper::fixed_to_float((*pos_info_i).y_offset); let x_advance = Shaper::fixed_to_float((*pos_info_i).x_advance); @@ -101,7 +108,7 @@ impl ShapedGlyphData { } else { // adjust the pen.. if y_advance > Au(0) { - *y_pos = *y_pos - y_advance; + *y_pos -= y_advance; } Some(Point2D::new(x_offset, *y_pos - y_offset)) @@ -110,7 +117,7 @@ impl ShapedGlyphData { ShapedGlyphEntry { codepoint: (*glyph_info_i).codepoint as GlyphId, advance: x_advance, - offset: offset, + offset, } } } @@ -136,6 +143,7 @@ impl Drop for Shaper { } impl Shaper { + #[allow(clippy::not_unsafe_ptr_arg_deref)] // Has an unsafe block inside pub fn new(font: *const Font) -> Shaper { unsafe { let hb_face: *mut hb_face_t = hb_face_create_for_tables( @@ -165,9 +173,9 @@ impl Shaper { ); Shaper { - hb_face: hb_face, - hb_font: hb_font, - font: font, + hb_face, + hb_font, + font, } } } @@ -415,7 +423,7 @@ impl Shaper { glyphs: &mut GlyphStore, buffer: *mut hb_buffer_t, ) { - let glyph_data = ShapedGlyphData::new(buffer); + let glyph_data = unsafe { ShapedGlyphData::new(buffer) }; let glyph_count = glyph_data.len(); let byte_max = text.len(); @@ -485,7 +493,7 @@ impl Shaper { } // if no glyphs were found yet, extend the char byte range more. - if glyph_span.len() == 0 { + if glyph_span.is_empty() { continue; } @@ -508,8 +516,8 @@ impl Shaper { // span or reach the end of the text. } - assert!(byte_range.len() > 0); - assert!(glyph_span.len() > 0); + assert!(!byte_range.is_empty()); + assert!(!glyph_span.is_empty()); // Now byte_range is the ligature clump formed by the glyphs in glyph_span. // We will save these glyphs to the glyph store at the index of the first byte. @@ -580,7 +588,7 @@ impl Shaper { options: &ShapingOptions, ) -> Au { if let Some(letter_spacing) = options.letter_spacing { - advance = advance + letter_spacing; + advance += letter_spacing; }; // CSS 2.1 § 16.4 states that "word spacing affects each space (U+0020) and non-breaking @@ -654,13 +662,10 @@ extern "C" fn glyph_h_advance_func( fn glyph_space_advance(font: *const Font) -> (hb_codepoint_t, f64) { let space_unicode = ' '; - let space_glyph: hb_codepoint_t; - match unsafe { (*font).glyph_index(space_unicode) } { - Some(g) => { - space_glyph = g as hb_codepoint_t; - }, + let space_glyph: hb_codepoint_t = match unsafe { (*font).glyph_index(space_unicode) } { + Some(g) => g as hb_codepoint_t, None => panic!("No space info"), - } + }; let space_advance = unsafe { (*font).glyph_h_advance(space_glyph as GlyphId) }; (space_glyph, space_advance) } diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 011ba784107..a40d82387a9 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -129,7 +129,7 @@ impl<'a> Iterator for NaturalWordSliceIterator<'a> { if !byte_range.is_empty() { Some(TextRunSlice { - glyphs: &*slice_glyphs.glyph_store, + glyphs: &slice_glyphs.glyph_store, offset: slice_range_begin, range: byte_range, }) @@ -172,7 +172,7 @@ impl<'a> Iterator for CharacterSliceIterator<'a> { let index_within_glyph_run = byte_start - glyph_run.range.begin(); Some(TextRunSlice { - glyphs: &*glyph_run.glyph_store, + glyphs: &glyph_run.glyph_store, offset: glyph_run.range.begin(), range: Range::new(index_within_glyph_run, byte_len), }) @@ -197,7 +197,7 @@ impl<'a> TextRun { font_key: font.font_key, pt_size: font.descriptor.pt_size, glyphs: Arc::new(glyphs), - bidi_level: bidi_level, + bidi_level, extra_word_spacing: Au(0), }, break_at_zero, @@ -217,7 +217,7 @@ impl<'a> TextRun { let mut break_at_zero = false; if breaker.is_none() { - if text.len() == 0 { + if text.is_empty() { return (glyphs, true); } *breaker = Some(LineBreakLeafIter::new(text, 0)); @@ -225,6 +225,16 @@ impl<'a> TextRun { let breaker = breaker.as_mut().unwrap(); + let mut push_range = |range: &std::ops::Range, options: &ShapingOptions| { + glyphs.push(GlyphRun { + glyph_store: font.shape_text(&text[range.clone()], &options), + range: Range::new( + ByteIndex(range.start as isize), + ByteIndex(range.len() as isize), + ), + }); + }; + while !finished { let (idx, _is_hard_break) = breaker.next(text); if idx == text.len() { @@ -240,9 +250,9 @@ impl<'a> TextRun { // Split off any trailing whitespace into a separate glyph run. let mut whitespace = slice.end..slice.end; - if let Some((i, _)) = word - .char_indices() - .rev() + let mut rev_char_indices = word.char_indices().rev().peekable(); + let ends_with_newline = rev_char_indices.peek().map_or(false, |&(_, c)| c == '\n'); + if let Some((i, _)) = rev_char_indices .take_while(|&(_, c)| char_is_whitespace(c)) .last() { @@ -253,27 +263,29 @@ impl<'a> TextRun { // keep-all, try increasing the slice. continue; } - if slice.len() > 0 { - glyphs.push(GlyphRun { - glyph_store: font.shape_text(&text[slice.clone()], options), - range: Range::new( - ByteIndex(slice.start as isize), - ByteIndex(slice.len() as isize), - ), - }); + if !slice.is_empty() { + push_range(&slice, options); } - if whitespace.len() > 0 { - let mut options = options.clone(); + if !whitespace.is_empty() { + let mut options = *options; options .flags .insert(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG); - glyphs.push(GlyphRun { - glyph_store: font.shape_text(&text[whitespace.clone()], &options), - range: Range::new( - ByteIndex(whitespace.start as isize), - ByteIndex(whitespace.len() as isize), - ), - }); + + // The breaker breaks after every newline, so either there is none, + // or there is exactly one at the very end. In the latter case, + // split it into a different run. That's because shaping considers + // a newline to have the same advance as a space, but during layout + // we want to treat the newline as having no advance. + if ends_with_newline { + whitespace.end -= 1; + if !whitespace.is_empty() { + push_range(&whitespace, &options); + } + whitespace.start = whitespace.end; + whitespace.end += 1; + } + push_range(&whitespace, &options); } slice.start = whitespace.end; } @@ -348,7 +360,9 @@ impl<'a> TextRun { } } - if let Ok(result) = (&**self.glyphs).binary_search_by(|current| current.compare(&index)) + if let Ok(result) = self + .glyphs + .binary_search_by(|current| current.compare(&index)) { index_of_first_glyph_run_cache.set(Some((self_ptr, index, result))); Some(result) @@ -396,7 +410,7 @@ impl<'a> TextRun { }; NaturalWordSliceIterator { glyphs: &self.glyphs[..], - index: index, + index, range: *range, reverse: false, } @@ -424,9 +438,9 @@ impl<'a> TextRun { }; NaturalWordSliceIterator { glyphs: &self.glyphs[..], - index: index, + index, range: *range, - reverse: reverse, + reverse, } } @@ -445,7 +459,7 @@ impl<'a> TextRun { CharacterSliceIterator { text: &self.text, glyph_run: first_glyph_run, - glyph_run_iter: glyph_run_iter, + glyph_run_iter, range: *range, } } diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs index a2644b8b302..be9ba144dca 100644 --- a/components/gfx/text/util.rs +++ b/components/gfx/text/util.rs @@ -113,12 +113,7 @@ pub fn fixed_to_float(before: usize, f: i32) -> f64 { } pub fn is_bidi_control(c: char) -> bool { - match c { - '\u{202A}'..='\u{202E}' => true, - '\u{2066}'..='\u{2069}' => true, - '\u{200E}' | '\u{200F}' | '\u{061C}' => true, - _ => false, - } + matches!(c, '\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}' | '\u{200E}' | '\u{200F}' | '\u{061C}') } pub fn unicode_plane(codepoint: char) -> u32 { diff --git a/components/hyper_serde/lib.rs b/components/hyper_serde/lib.rs index 22f79c8ad65..bb48b1c47e5 100644 --- a/components/hyper_serde/lib.rs +++ b/components/hyper_serde/lib.rs @@ -531,7 +531,7 @@ impl<'a> Serialize for Ser<'a, Mime> { where S: Serializer, { - serializer.serialize_str(&self.v.as_ref()) + serializer.serialize_str(self.v.as_ref()) } } diff --git a/components/layout/block.rs b/components/layout/block.rs index e4463072b32..b0bd785ac3a 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -1761,7 +1761,7 @@ impl BlockFlow { // If you remove the might_have_floats_in conditional, this will go off. // TODO(servo#30572) revert to debug_assert!() once underlying bug is fixed #[cfg(debug_assertions)] - if !(!self.is_inline_flex_item()) { + if self.is_inline_flex_item() { log::warn!("debug assertion failed! !self.is_inline_flex_item()"); } diff --git a/components/layout/construct.rs b/components/layout/construct.rs index f2fa3cb9104..2a615c944b3 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -199,7 +199,7 @@ impl InlineBlockSplit { fragment_accumulator, InlineFragmentsAccumulator::from_inline_node(node, style_context), ) - .to_intermediate_inline_fragments::(style_context), + .get_intermediate_inline_fragments::(style_context), flow, }; @@ -305,7 +305,7 @@ impl InlineFragmentsAccumulator { .push_descendants(fragments.absolute_descendants); } - fn to_intermediate_inline_fragments<'dom, N>( + fn get_intermediate_inline_fragments<'dom, N>( self, context: &SharedStyleContext, ) -> IntermediateInlineFragments @@ -482,7 +482,9 @@ where node: &ConcreteThreadSafeLayoutNode, ) { let mut fragments = fragment_accumulator - .to_intermediate_inline_fragments::(self.style_context()); + .get_intermediate_inline_fragments::( + self.style_context(), + ); if fragments.is_empty() { return; }; @@ -1079,7 +1081,7 @@ where ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: opt_inline_block_splits, fragments: fragment_accumulator - .to_intermediate_inline_fragments::( + .get_intermediate_inline_fragments::( self.style_context(), ), }); @@ -1196,7 +1198,7 @@ where ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), fragments: fragment_accumulator - .to_intermediate_inline_fragments::(context), + .get_intermediate_inline_fragments::(context), }); ConstructionResult::ConstructionItem(construction_item) } @@ -1246,7 +1248,7 @@ where ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), fragments: fragment_accumulator - .to_intermediate_inline_fragments::( + .get_intermediate_inline_fragments::( style_context, ), }); diff --git a/components/layout/context.rs b/components/layout/context.rs index eb25b5bd51d..d43210c141b 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -55,6 +55,9 @@ pub fn malloc_size_of_persistent_local_context(ops: &mut MallocSizeOfOps) -> usi }) } +type WebrenderImageCache = + HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault>; + /// Layout information shared among all workers. This must be thread-safe. pub struct LayoutContext<'a> { /// The pipeline id of this LayoutContext. @@ -73,11 +76,7 @@ pub struct LayoutContext<'a> { pub font_cache_thread: Mutex, /// A cache of WebRender image info. - pub webrender_image_cache: Arc< - RwLock< - HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault>, - >, - >, + pub webrender_image_cache: Arc>, /// Paint worklets pub registered_painters: &'a dyn RegisteredPainters, diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs index 5e5738a0f4b..0f064c9c3aa 100644 --- a/components/layout/display_list/background.rs +++ b/components/layout/display_list/background.rs @@ -2,6 +2,8 @@ * 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/. */ +#![allow(clippy::too_many_arguments)] + use app_units::Au; use euclid::default::{Point2D, Rect, SideOffsets2D, Size2D}; use style::computed_values::background_attachment::single_value::T as BackgroundAttachment; diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index c813def2142..c2cd9f19c21 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -8,6 +8,8 @@ //! list building, as the actual painting does not happen here—only deciding *what* we're going to //! paint. +#![allow(clippy::too_many_arguments)] + use std::default::Default; use std::sync::Arc; use std::{f32, mem}; @@ -27,6 +29,7 @@ use log::{debug, warn}; use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image_cache::UsePlaceholder; use range::Range; +use script_traits::compositor::ScrollSensitivity; use servo_config::opts; use servo_geometry::{self, MaxRect}; use style::color::AbsoluteColor; @@ -49,7 +52,7 @@ use webrender_api::units::{LayoutRect, LayoutTransform, LayoutVector2D}; use webrender_api::{ self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF, ColorU, ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LineStyle, NinePatchBorder, - NinePatchBorderSource, NormalBorder, PropertyBinding, ScrollSensitivity, StickyOffsetBounds, + NinePatchBorderSource, NormalBorder, PropertyBinding, StickyOffsetBounds, }; use crate::block::BlockFlow; @@ -80,7 +83,7 @@ static THREAD_TINT_COLORS: [ColorF; 8] = [ a: 0.7, }, ColorF { - r: 255.0 / 255.0, + r: 1.0, g: 212.0 / 255.0, b: 83.0 / 255.0, a: 0.7, @@ -110,7 +113,7 @@ static THREAD_TINT_COLORS: [ColorF; 8] = [ a: 0.7, }, ColorF { - r: 255.0 / 255.0, + r: 1.0, g: 249.0 / 255.0, b: 201.0 / 255.0, a: 0.7, @@ -382,6 +385,7 @@ impl<'a> DisplayListBuildState<'a> { &self, clip_rect: Rect, node: OpaqueNode, + unique_id: u64, cursor: Option, section: DisplayListSection, ) -> BaseDisplayItem { @@ -395,6 +399,7 @@ impl<'a> DisplayListBuildState<'a> { self.create_base_display_item_with_clipping_and_scrolling( clip_rect, node, + unique_id, cursor, section, clipping_and_scrolling, @@ -405,12 +410,17 @@ impl<'a> DisplayListBuildState<'a> { &self, clip_rect: Rect, node: OpaqueNode, + unique_id: u64, cursor: Option, section: DisplayListSection, clipping_and_scrolling: ClippingAndScrolling, ) -> BaseDisplayItem { BaseDisplayItem::new( - DisplayItemMetadata { node, cursor }, + DisplayItemMetadata { + node, + unique_id, + cursor, + }, clip_rect.to_layout(), section, self.current_stacking_context_id, @@ -443,7 +453,7 @@ impl<'a> DisplayListBuildState<'a> { let mut list = Vec::new(); let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root()); - self.to_display_list_for_stacking_context(&mut list, root_context); + self.move_to_display_list_for_stacking_context(&mut list, root_context); DisplayList { list, @@ -451,7 +461,7 @@ impl<'a> DisplayListBuildState<'a> { } } - fn to_display_list_for_stacking_context( + fn move_to_display_list_for_stacking_context( &mut self, list: &mut Vec, stacking_context: StackingContext, @@ -473,7 +483,7 @@ impl<'a> DisplayListBuildState<'a> { .into_iter() .map(|index| index.to_define_item()), ); - self.to_display_list_for_items(list, child_items, info.children); + self.move_to_display_list_for_items(list, child_items, info.children); } else { let (push_item, pop_item) = stacking_context.to_display_list_items(); list.push(push_item); @@ -482,12 +492,12 @@ impl<'a> DisplayListBuildState<'a> { .into_iter() .map(|index| index.to_define_item()), ); - self.to_display_list_for_items(list, child_items, info.children); + self.move_to_display_list_for_items(list, child_items, info.children); list.push(pop_item); } } - fn to_display_list_for_items( + fn move_to_display_list_for_items( &mut self, list: &mut Vec, mut child_items: Vec, @@ -509,7 +519,7 @@ impl<'a> DisplayListBuildState<'a> { .map_or(false, |child| child.z_index < 0) { let context = child_stacking_contexts.next().unwrap(); - self.to_display_list_for_stacking_context(list, context); + self.move_to_display_list_for_stacking_context(list, context); } // Step 4: Block backgrounds and borders. @@ -524,7 +534,7 @@ impl<'a> DisplayListBuildState<'a> { child.context_type == StackingContextType::PseudoFloat }) { let context = child_stacking_contexts.next().unwrap(); - self.to_display_list_for_stacking_context(list, context); + self.move_to_display_list_for_stacking_context(list, context); } // Step 6 & 7: Content and inlines that generate stacking contexts. @@ -536,7 +546,7 @@ impl<'a> DisplayListBuildState<'a> { // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices. for child in child_stacking_contexts { - self.to_display_list_for_stacking_context(list, child); + self.move_to_display_list_for_stacking_context(list, child); } // Step 10: Outlines. @@ -700,6 +710,7 @@ impl Fragment { let base = state.create_base_display_item( bounds, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), display_list_section, ); @@ -840,6 +851,7 @@ impl Fragment { let base = state.create_base_display_item( placement.clip_rect, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), display_list_section, ); @@ -962,6 +974,7 @@ impl Fragment { let base = state.create_base_display_item( placement.clip_rect, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), display_list_section, ); @@ -1017,7 +1030,7 @@ impl Fragment { }; DisplayItem::RadialGradient(CommonDisplayItem::with_data(base, item, stops)) }, - Gradient::Conic { .. } => unimplemented!(), + Gradient::Conic { .. } => return, }; state.add_display_item(display_item); }); @@ -1038,6 +1051,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), display_list_section, ); @@ -1124,6 +1138,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), display_list_section, ); @@ -1219,7 +1234,7 @@ impl Fragment { )?; width = image.width; height = image.height; - NinePatchBorderSource::Image(image.key?) + NinePatchBorderSource::Image(image.key?, ImageRendering::Auto) }, Image::PaintWorklet(ref paint_worklet) => { let image = self.get_webrender_image_for_paint_worklet( @@ -1230,7 +1245,7 @@ impl Fragment { )?; width = image.width; height = image.height; - NinePatchBorderSource::Image(image.key?) + NinePatchBorderSource::Image(image.key?, ImageRendering::Auto) }, Image::Gradient(ref gradient) => match **gradient { Gradient::Linear { @@ -1271,7 +1286,7 @@ impl Fragment { stops = radial_stops; NinePatchBorderSource::RadialGradient(wr_gradient) }, - Gradient::Conic { .. } => unimplemented!(), + Gradient::Conic { .. } => return None, }, _ => return None, }; @@ -1286,7 +1301,6 @@ impl Fragment { fill: border_image_fill, repeat_horizontal: border_image_repeat.0.to_layout(), repeat_vertical: border_image_repeat.1.to_layout(), - outset: SideOffsets2D::zero(), }); state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data( base, @@ -1338,6 +1352,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), DisplayListSection::Outlines, ); @@ -1370,6 +1385,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), DisplayListSection::Content, ); @@ -1400,12 +1416,13 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(style, Cursor::Default), DisplayListSection::Content, ); // TODO(gw): Use a better estimate for wavy line thickness. let area = baseline.to_layout(); - let wavy_line_thickness = (0.33 * area.size.height).ceil(); + let wavy_line_thickness = (0.33 * area.size().height).ceil(); state.add_display_item(DisplayItem::Line(CommonDisplayItem::new( base, webrender_api::LineDisplayItem { @@ -1430,6 +1447,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(&self.style, Cursor::Default), DisplayListSection::Content, ); @@ -1473,6 +1491,7 @@ impl Fragment { let base = state.create_base_display_item( stacking_relative_border_box, self.node, + self.unique_id(), get_cursor(&self.style, Cursor::Default), display_list_section, ); @@ -1520,6 +1539,7 @@ impl Fragment { let base = state.create_base_display_item( insertion_point_bounds, self.node, + self.unique_id(), get_cursor(&self.style, cursor), display_list_section, ); @@ -1707,6 +1727,7 @@ impl Fragment { let base = state.create_base_display_item_with_clipping_and_scrolling( content_size, self.node, + self.unique_id(), // FIXME(emilio): Why does this ignore pointer-events? get_cursor(&self.style, Cursor::Default).or(Some(Cursor::Default)), display_list_section, @@ -1771,6 +1792,7 @@ impl Fragment { state.create_base_display_item( stacking_relative_border_box, self.node, + self.unique_id(), get_cursor(&self.style, Cursor::Default), DisplayListSection::Content, ) @@ -1857,7 +1879,7 @@ impl Fragment { // looks bogus. state.iframe_sizes.insert( browsing_context_id, - euclid::Size2D::new(bounds.size.width, bounds.size.height), + euclid::Size2D::new(bounds.size().width, bounds.size().height), ); let pipeline_id = match fragment_info.pipeline_id { @@ -2065,6 +2087,7 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(&self.style, cursor), DisplayListSection::Content, ); @@ -2228,13 +2251,14 @@ impl Fragment { let base = state.create_base_display_item( clip, self.node, + self.unique_id(), get_cursor(&self.style, Cursor::Default), DisplayListSection::Content, ); // TODO(gw): Use a better estimate for wavy line thickness. let area = stacking_relative_box.to_layout(); - let wavy_line_thickness = (0.33 * area.size.height).ceil(); + let wavy_line_thickness = (0.33 * area.size().height).ceil(); state.add_display_item(DisplayItem::Line(CommonDisplayItem::new( base, webrender_api::LineDisplayItem { @@ -2642,10 +2666,10 @@ impl BlockFlow { // The margins control which edges have sticky behavior. let sticky_frame_data = StickyFrameData { margins: SideOffsets2D::new( - sticky_position.top.to_option().map(|v| v.to_f32_px()), - sticky_position.right.to_option().map(|v| v.to_f32_px()), - sticky_position.bottom.to_option().map(|v| v.to_f32_px()), - sticky_position.left.to_option().map(|v| v.to_f32_px()), + sticky_position.top.as_option().map(|v| v.to_f32_px()), + sticky_position.right.as_option().map(|v| v.to_f32_px()), + sticky_position.bottom.as_option().map(|v| v.to_f32_px()), + sticky_position.left.as_option().map(|v| v.to_f32_px()), ), vertical_offset_bounds, horizontal_offset_bounds, @@ -2943,8 +2967,15 @@ impl BaseFlow { let mut color = THREAD_TINT_COLORS[thread_id as usize % THREAD_TINT_COLORS.len()]; color.a = 1.0; - let base = - state.create_base_display_item(self.clip, node, None, DisplayListSection::Content); + let base = state.create_base_display_item( + self.clip, + node, + // This item will never become a spatial tree node, so it's fine + // to pass 0 here. + 0, + None, + DisplayListSection::Content, + ); let bounds = stacking_context_relative_bounds.inflate(Au::from_px(2), Au::from_px(2)); state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data( base, @@ -3121,6 +3152,6 @@ trait ToF32Px { impl ToF32Px for Rect { type Output = LayoutRect; fn to_f32_px(&self) -> LayoutRect { - LayoutRect::from_untyped(&servo_geometry::au_rect_to_f32_rect(*self)) + LayoutRect::from_untyped(&servo_geometry::au_rect_to_f32_rect(*self).to_box2d()) } } diff --git a/components/layout/display_list/conversions.rs b/components/layout/display_list/conversions.rs index 69c68951e7b..30af153fe20 100644 --- a/components/layout/display_list/conversions.rs +++ b/components/layout/display_list/conversions.rs @@ -139,7 +139,7 @@ impl ToLayout for Point2D { impl ToLayout for Rect { type Type = wr::units::LayoutRect; fn to_layout(&self) -> Self::Type { - wr::units::LayoutRect::new(self.origin.to_layout(), self.size.to_layout()) + wr::units::LayoutRect::from_origin_and_size(self.origin.to_layout(), self.size.to_layout()) } } diff --git a/components/layout/display_list/items.rs b/components/layout/display_list/items.rs index 9f1d6d76df5..d7fbcaf060b 100644 --- a/components/layout/display_list/items.rs +++ b/components/layout/display_list/items.rs @@ -12,6 +12,8 @@ //! They are therefore not exactly analogous to constructs like Skia pictures, which consist of //! low-level drawing primitives. +#![allow(clippy::too_many_arguments)] + use std::cmp::Ordering; use std::collections::HashMap; use std::{f32, fmt}; @@ -22,7 +24,7 @@ use gfx_traits::print_tree::PrintTree; use gfx_traits::{self, StackingContextId}; use msg::constellation_msg::PipelineId; use net_traits::image::base::Image; -use script_traits::compositor::ScrollTreeNodeId; +use script_traits::compositor::{ScrollSensitivity, ScrollTreeNodeId}; use serde::Serialize; use servo_geometry::MaxRect; use style::computed_values::_servo_top_layer::T as InTopLayer; @@ -30,9 +32,9 @@ pub use style::dom::OpaqueNode; use webrender_api as wr; use webrender_api::units::{LayoutPixel, LayoutRect, LayoutTransform}; use webrender_api::{ - BorderRadius, ClipChainId, ClipId, ClipMode, CommonItemProperties, ComplexClipRegion, - ExternalScrollId, FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, - PrimitiveFlags, ScrollSensitivity, Shadow, SpatialId, StickyOffsetBounds, TransformStyle, + BorderRadius, ClipChainId, ClipMode, CommonItemProperties, ComplexClipRegion, ExternalScrollId, + FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags, Shadow, + SpatialId, StickyOffsetBounds, TransformStyle, }; /// The factor that we multiply the blur radius by in order to inflate the boundaries of display @@ -477,6 +479,7 @@ impl BaseDisplayItem { BaseDisplayItem { metadata: DisplayItemMetadata { node: OpaqueNode(0), + unique_id: 0, cursor: None, }, // Create a rectangle of maximal size. @@ -493,7 +496,7 @@ impl BaseDisplayItem { pub fn empty_common_item_properties() -> CommonItemProperties { CommonItemProperties { clip_rect: LayoutRect::max_rect(), - clip_id: ClipId::root(wr::PipelineId::dummy()), + clip_chain_id: ClipChainId::INVALID, spatial_id: SpatialId::root_scroll_node(wr::PipelineId::dummy()), flags: PrimitiveFlags::empty(), } @@ -551,6 +554,8 @@ impl fmt::Debug for ClippingRegion { pub struct DisplayItemMetadata { /// The DOM node from which this display item originated. pub node: OpaqueNode, + /// The unique fragment id of the fragment of this item. + pub unique_id: u64, /// The value of the `cursor` property when the mouse hovers over this display item. If `None`, /// this display item is ineligible for pointer events (`pointer-events: none`). pub cursor: Option, diff --git a/components/layout/display_list/webrender_helpers.rs b/components/layout/display_list/webrender_helpers.rs index 04d8d825e06..fb5159b5cf0 100644 --- a/components/layout/display_list/webrender_helpers.rs +++ b/components/layout/display_list/webrender_helpers.rs @@ -10,12 +10,14 @@ use gfx_traits::WebRenderEpochToU16; use log::trace; use msg::constellation_msg::PipelineId; -use script_traits::compositor::{CompositorDisplayListInfo, ScrollTreeNodeId, ScrollableNodeInfo}; +use script_traits::compositor::{ + CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo, +}; use webrender_api::units::{LayoutPoint, LayoutSize, LayoutVector2D}; use webrender_api::{ self, ClipChainId, ClipId, CommonItemProperties, DisplayItem as WrDisplayItem, - DisplayListBuilder, Epoch, PrimitiveFlags, PropertyBinding, PushStackingContextDisplayItem, - RasterSpace, ReferenceFrameKind, SpaceAndClipInfo, SpatialId, StackingContext, + DisplayListBuilder, Epoch, HasScrollLinkedEffect, PrimitiveFlags, PropertyBinding, RasterSpace, + ReferenceFrameKind, SpaceAndClipInfo, SpatialId, SpatialTreeItemKey, }; use crate::display_list::items::{ @@ -32,7 +34,6 @@ impl<'a> ClipScrollState<'a> { fn new( clip_scroll_nodes: &'a mut Vec, compositor_info: CompositorDisplayListInfo, - builder: &mut DisplayListBuilder, ) -> Self { let mut state = ClipScrollState { clip_scroll_nodes, @@ -48,9 +49,7 @@ impl<'a> ClipScrollState<'a> { Some(state.compositor_info.root_reference_frame_id); state.clip_scroll_nodes[1].scroll_node_id = Some(state.compositor_info.root_scroll_node_id); - let root_clip_chain = - builder.define_clip_chain(None, [ClipId::root(state.compositor_info.pipeline_id)]); - + let root_clip_chain = ClipChainId::INVALID; state.add_clip_node_mapping(0, root_clip_chain); state.add_clip_node_mapping(1, root_clip_chain); @@ -100,6 +99,25 @@ impl<'a> ClipScrollState<'a> { self.clip_scroll_nodes[index].scroll_node_id = self.clip_scroll_nodes[parent_index].scroll_node_id } + + pub fn define_clip_chain( + &self, + builder: &mut DisplayListBuilder, + parent: ClipChainId, + clips: I, + ) -> ClipChainId + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone, + { + // We use INVALID to mean "no clipping", but that cannot be passed as an argument + // to `define_clip_chain()`, so it must be converted into `None`. + let parent = match parent { + ClipChainId::INVALID => None, + parent => Some(parent), + }; + builder.define_clip_chain(parent, clips) + } } /// Contentful paint, for the purpose of @@ -117,12 +135,18 @@ impl DisplayList { ) -> (DisplayListBuilder, CompositorDisplayListInfo, IsContentful) { let webrender_pipeline = pipeline_id.to_webrender(); let mut builder = DisplayListBuilder::new(webrender_pipeline); + builder.begin(); - let content_size = self.bounds().size; + let content_size = self.bounds().size(); let mut state = ClipScrollState::new( &mut self.clip_scroll_nodes, - CompositorDisplayListInfo::new(viewport_size, content_size, webrender_pipeline, epoch), - &mut builder, + CompositorDisplayListInfo::new( + viewport_size, + content_size, + webrender_pipeline, + epoch, + ScrollSensitivity::ScriptAndInputEvents, + ), ); let mut is_contentful = IsContentful(false); @@ -135,6 +159,15 @@ impl DisplayList { } impl DisplayItem { + fn get_spatial_tree_item_key( + &self, + builder: &DisplayListBuilder, + node_index: usize, + ) -> SpatialTreeItemKey { + let pipeline_tag = (builder.pipeline_id.0 as u64) << 32 | builder.pipeline_id.1 as u64; + SpatialTreeItemKey::new(pipeline_tag, node_index as u64) + } + fn convert_to_webrender( &mut self, state: &mut ClipScrollState, @@ -161,7 +194,7 @@ impl DisplayItem { CommonItemProperties { clip_rect: base.clip_rect, spatial_id: current_scroll_node_id.spatial_id, - clip_id: ClipId::ClipChain(current_clip_chain_id), + clip_chain_id: current_clip_chain_id, // TODO(gw): Make use of the WR backface visibility functionality. flags: PrimitiveFlags::default(), } @@ -185,12 +218,10 @@ impl DisplayItem { ); builder.push_hit_test( - &CommonItemProperties { - clip_rect: bounds, - spatial_id: current_scroll_node_id.spatial_id, - clip_id: ClipId::ClipChain(current_clip_chain_id), - flags: PrimitiveFlags::default(), - }, + bounds, + current_clip_chain_id, + current_scroll_node_id.spatial_id, + PrimitiveFlags::default(), (hit_test_index as u64, state.compositor_info.epoch.as_u16()), ); }; @@ -262,7 +293,7 @@ impl DisplayItem { builder.push_shadow( &SpaceAndClipInfo { spatial_id: common.spatial_id, - clip_id: common.clip_id, + clip_chain_id: common.clip_chain_id, }, item.shadow, true, @@ -281,7 +312,7 @@ impl DisplayItem { common.clip_rect, &SpaceAndClipInfo { spatial_id: common.spatial_id, - clip_id: common.clip_id, + clip_chain_id: common.clip_chain_id, }, item.iframe.to_webrender(), true, @@ -309,6 +340,7 @@ impl DisplayItem { ReferenceFrameKind::Transform { is_2d_scale_translation: false, should_snap: false, + paired_with_perspective: false, }, ), (Some(t), Some(p)) => ( @@ -320,15 +352,16 @@ impl DisplayItem { (None, None) => unreachable!(), }; + let index = frame_index.to_index(); let new_spatial_id = builder.push_reference_frame( - stacking_context.bounds.origin, + stacking_context.bounds.min, current_scroll_node_id.spatial_id, stacking_context.transform_style, PropertyBinding::Value(transform), ref_frame, + self.get_spatial_tree_item_key(builder, index), ); - let index = frame_index.to_index(); state.add_clip_node_mapping(index, current_clip_chain_id); state.register_spatial_node( index, @@ -337,37 +370,32 @@ impl DisplayItem { None, ); - bounds.origin = LayoutPoint::zero(); + bounds.min = LayoutPoint::zero(); new_spatial_id } else { current_scroll_node_id.spatial_id }; - if !stacking_context.filters.is_empty() { - builder.push_item(&WrDisplayItem::SetFilterOps); - builder.push_iter(&stacking_context.filters); - } - // TODO(jdm): WebRender now requires us to create stacking context items // with the IS_BLEND_CONTAINER flag enabled if any children // of the stacking context have a blend mode applied. // This will require additional tracking during layout // before we start collecting stacking contexts so that // information will be available when we reach this point. - let wr_item = PushStackingContextDisplayItem { - origin: bounds.origin, + builder.push_stacking_context( + bounds.min, spatial_id, - prim_flags: PrimitiveFlags::default(), - stacking_context: StackingContext { - transform_style: stacking_context.transform_style, - mix_blend_mode: stacking_context.mix_blend_mode, - clip_id: None, - raster_space: RasterSpace::Screen, - flags: Default::default(), - }, - }; + PrimitiveFlags::default(), + None, + stacking_context.transform_style, + stacking_context.mix_blend_mode, + &stacking_context.filters, + &[], + &[], + RasterSpace::Screen, + Default::default(), + ); - builder.push_item(&WrDisplayItem::PushStackingContext(wr_item)); IsContentful(false) }, DisplayItem::PopStackingContext(ref item) => { @@ -386,43 +414,38 @@ impl DisplayItem { let parent_spatial_id = state.webrender_spatial_id_for_index(parent_index); let parent_clip_chain_id = state.webrender_clip_id_for_index(parent_index); - let parent_space_and_clip_info = SpaceAndClipInfo { - clip_id: ClipId::root(state.compositor_info.pipeline_id), - spatial_id: parent_spatial_id, - }; - match node.node_type { ClipScrollNodeType::Clip(clip_type) => { let clip_id = match clip_type { ClipType::Rect => { - builder.define_clip_rect(&parent_space_and_clip_info, item_rect) + builder.define_clip_rect(parent_spatial_id, item_rect) + }, + ClipType::Rounded(complex) => { + builder.define_clip_rounded_rect(parent_spatial_id, complex) }, - ClipType::Rounded(complex) => builder - .define_clip_rounded_rect(&parent_space_and_clip_info, complex), }; let clip_chain_id = - builder.define_clip_chain(Some(parent_clip_chain_id), [clip_id]); + state.define_clip_chain(builder, parent_clip_chain_id, [clip_id]); state.add_clip_node_mapping(index, clip_chain_id); state.add_spatial_node_mapping_to_parent_index(index, parent_index); }, ClipScrollNodeType::ScrollFrame(scroll_sensitivity, external_id) => { - let clip_id = - builder.define_clip_rect(&parent_space_and_clip_info, item_rect); + let clip_id = builder.define_clip_rect(parent_spatial_id, item_rect); let clip_chain_id = - builder.define_clip_chain(Some(parent_clip_chain_id), [clip_id]); + state.define_clip_chain(builder, parent_clip_chain_id, [clip_id]); state.add_clip_node_mapping(index, clip_chain_id); - let spatial_id = builder - .define_scroll_frame( - &parent_space_and_clip_info, - external_id, - node.content_rect, - item_rect, - scroll_sensitivity, - LayoutVector2D::zero(), - ) - .spatial_id; + let spatial_id = builder.define_scroll_frame( + parent_spatial_id, + external_id, + node.content_rect, + item_rect, + LayoutVector2D::zero(), /* external_scroll_offset */ + 0, /* scroll_offset_generation */ + HasScrollLinkedEffect::No, + self.get_spatial_tree_item_key(builder, index), + ); state.register_spatial_node( index, @@ -430,7 +453,7 @@ impl DisplayItem { Some(parent_index), Some(ScrollableNodeInfo { external_id, - scrollable_size: node.content_rect.size - item_rect.size, + scrollable_size: node.content_rect.size() - item_rect.size(), scroll_sensitivity, offset: LayoutVector2D::zero(), }), @@ -444,7 +467,8 @@ impl DisplayItem { sticky_data.margins, sticky_data.vertical_offset_bounds, sticky_data.horizontal_offset_bounds, - LayoutVector2D::zero(), + LayoutVector2D::zero(), /* previously_applied_offset */ + self.get_spatial_tree_item_key(builder, index), ); state.add_clip_node_mapping(index, parent_clip_chain_id); diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 1f5b7104780..29152507c12 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -250,7 +250,7 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState); /// If this is a float, places it. The default implementation does nothing. - fn place_float_if_applicable<'a>(&mut self) {} + fn place_float_if_applicable(&mut self) {} /// Assigns block-sizes in-order; or, if this is a float, places the float. The default /// implementation simply assigns block-sizes if this flow might have floats in. Returns true @@ -505,6 +505,7 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static { } } +#[allow(clippy::wrong_self_convention)] pub trait ImmutableFlowUtils { // Convenience functions @@ -603,18 +604,18 @@ pub enum FlowClass { impl FlowClass { fn is_block_like(self) -> bool { - match self { + matches!( + self, FlowClass::Block | - FlowClass::ListItem | - FlowClass::Table | - FlowClass::TableRowGroup | - FlowClass::TableRow | - FlowClass::TableCaption | - FlowClass::TableCell | - FlowClass::TableWrapper | - FlowClass::Flex => true, - _ => false, - } + FlowClass::ListItem | + FlowClass::Table | + FlowClass::TableRowGroup | + FlowClass::TableRow | + FlowClass::TableCaption | + FlowClass::TableCell | + FlowClass::TableWrapper | + FlowClass::Flex + ) } } @@ -1232,50 +1233,32 @@ impl<'a> ImmutableFlowUtils for &'a dyn Flow { /// Returns true if this flow is a table row flow. fn is_table_row(self) -> bool { - match self.class() { - FlowClass::TableRow => true, - _ => false, - } + matches!(self.class(), FlowClass::TableRow) } /// Returns true if this flow is a table cell flow. fn is_table_cell(self) -> bool { - match self.class() { - FlowClass::TableCell => true, - _ => false, - } + matches!(self.class(), FlowClass::TableCell) } /// Returns true if this flow is a table colgroup flow. fn is_table_colgroup(self) -> bool { - match self.class() { - FlowClass::TableColGroup => true, - _ => false, - } + matches!(self.class(), FlowClass::TableColGroup) } /// Returns true if this flow is a table flow. fn is_table(self) -> bool { - match self.class() { - FlowClass::Table => true, - _ => false, - } + matches!(self.class(), FlowClass::Table) } /// Returns true if this flow is a table caption flow. fn is_table_caption(self) -> bool { - match self.class() { - FlowClass::TableCaption => true, - _ => false, - } + matches!(self.class(), FlowClass::TableCaption) } /// Returns true if this flow is a table rowgroup flow. fn is_table_rowgroup(self) -> bool { - match self.class() { - FlowClass::TableRowGroup => true, - _ => false, - } + matches!(self.class(), FlowClass::TableRowGroup) } /// Returns the number of children that this flow possesses. @@ -1285,18 +1268,12 @@ impl<'a> ImmutableFlowUtils for &'a dyn Flow { /// Returns true if this flow is a block flow. fn is_block_flow(self) -> bool { - match self.class() { - FlowClass::Block => true, - _ => false, - } + matches!(self.class(), FlowClass::Block) } /// Returns true if this flow is an inline flow. fn is_inline_flow(self) -> bool { - match self.class() { - FlowClass::Inline => true, - _ => false, - } + matches!(self.class(), FlowClass::Inline) } /// Dumps the flow tree for debugging. @@ -1392,7 +1369,7 @@ impl MutableOwnedFlowUtils for FlowRef { for descendant_link in abs_descendants.descendant_links.iter_mut() { // TODO(servo#30573) revert to debug_assert!() once underlying bug is fixed #[cfg(debug_assertions)] - if !(!descendant_link.has_reached_containing_block) { + if descendant_link.has_reached_containing_block { log::warn!("debug assertion failed! !descendant_link.has_reached_containing_block"); } let descendant_base = FlowRef::deref_mut(&mut descendant_link.flow).mut_base(); diff --git a/components/layout/flow_ref.rs b/components/layout/flow_ref.rs index b0955e66448..4657db77040 100644 --- a/components/layout/flow_ref.rs +++ b/components/layout/flow_ref.rs @@ -49,6 +49,7 @@ impl FlowRef { /// See . /// Use Arc::get_mut instead when possible (e.g. on an Arc that was just created). #[allow(unsafe_code)] + #[allow(clippy::should_implement_trait)] pub fn deref_mut(this: &mut FlowRef) -> &mut dyn Flow { let ptr: *const dyn Flow = &*this.0; unsafe { &mut *(ptr as *mut dyn Flow) } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 6884d4cbe6b..40233a2fc93 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -1592,9 +1592,8 @@ impl Fragment { /// Returns true if and only if this fragment is a generated content fragment. pub fn is_unscanned_generated_content(&self) -> bool { match self.specific { - SpecificFragmentInfo::GeneratedContent(ref content) => match **content { - GeneratedContentInfo::Empty => false, - _ => true, + SpecificFragmentInfo::GeneratedContent(ref content) => { + !matches!(**content, GeneratedContentInfo::Empty) }, _ => false, } @@ -1602,10 +1601,7 @@ impl Fragment { /// Returns true if and only if this is a scanned text fragment. pub fn is_scanned_text_fragment(&self) -> bool { - match self.specific { - SpecificFragmentInfo::ScannedText(..) => true, - _ => false, - } + matches!(self.specific, SpecificFragmentInfo::ScannedText(..)) } pub fn suppress_line_break_before(&self) -> bool { @@ -1972,8 +1968,8 @@ impl Fragment { // see if we're going to overflow the line. If so, perform a best-effort split. let mut remaining_range = slice.text_run_range(); let split_is_empty = inline_start_range.is_empty() && - !(self.requires_line_break_afterward_if_wrapping_on_newlines() && - !self.white_space().allow_wrap()); + (self.white_space().allow_wrap() || + !self.requires_line_break_afterward_if_wrapping_on_newlines()); if split_is_empty { // We're going to overflow the line. overflowing = true; @@ -2259,14 +2255,14 @@ impl Fragment { /// Returns true if this fragment is replaced content. pub fn is_replaced(&self) -> bool { - match self.specific { + matches!( + self.specific, SpecificFragmentInfo::Iframe(_) | - SpecificFragmentInfo::Canvas(_) | - SpecificFragmentInfo::Image(_) | - SpecificFragmentInfo::Media(_) | - SpecificFragmentInfo::Svg(_) => true, - _ => false, - } + SpecificFragmentInfo::Canvas(_) | + SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | + SpecificFragmentInfo::Svg(_) + ) } /// Returns true if this fragment is replaced content or an inline-block or false otherwise. @@ -2507,10 +2503,10 @@ impl Fragment { /// Returns true if this fragment is a hypothetical box. See CSS 2.1 § 10.3.7. pub fn is_hypothetical(&self) -> bool { - match self.specific { - SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => true, - _ => false, - } + matches!( + self.specific, + SpecificFragmentInfo::InlineAbsoluteHypothetical(_) + ) } /// Returns true if this fragment can merge with another immediately-following fragment or @@ -3069,10 +3065,7 @@ impl Fragment { } pub fn is_inline_absolute(&self) -> bool { - match self.specific { - SpecificFragmentInfo::InlineAbsolute(..) => true, - _ => false, - } + matches!(self.specific, SpecificFragmentInfo::InlineAbsolute(..)) } pub fn meld_with_next_inline_fragment(&mut self, next_fragment: &Fragment) { @@ -3141,11 +3134,11 @@ impl Fragment { /// `vertical-align` set to `top` or `bottom`. pub fn is_vertically_aligned_to_top_or_bottom(&self) -> bool { fn is_top_or_bottom(v: &VerticalAlign) -> bool { - match *v { + matches!( + *v, VerticalAlign::Keyword(VerticalAlignKeyword::Top) | - VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => true, - _ => false, - } + VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) + ) } if is_top_or_bottom(&self.style.get_box().vertical_align) { diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index 20e1b1ead0e..862e8c88191 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -307,7 +307,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { } // Truncate down counters. - for (_, counter) in &mut self.traversal.counters { + for counter in self.traversal.counters.values_mut() { counter.truncate_to_level(self.level); } self.traversal.list_item.truncate_to_level(self.level); diff --git a/components/layout/model.rs b/components/layout/model.rs index 557295de92a..c41666218ab 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -478,7 +478,7 @@ impl MaybeAuto { } #[inline] - pub fn to_option(&self) -> Option { + pub fn as_option(&self) -> Option { match *self { MaybeAuto::Specified(value) => Some(value), MaybeAuto::Auto => None, diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index cd15063ea57..26d7d429a25 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -29,16 +29,24 @@ const CHUNK_SIZE: usize = 16; pub type FlowList = SmallVec<[UnsafeFlow; CHUNK_SIZE]>; /// Vtable + pointer representation of a Flow trait object. -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Eq)] pub struct UnsafeFlow(*const dyn Flow); unsafe impl Sync for UnsafeFlow {} unsafe impl Send for UnsafeFlow {} +impl PartialEq for UnsafeFlow { + #[allow(clippy::ptr_eq)] + fn eq(&self, other: &Self) -> bool { + // Compare the pointers explicitly to avoid a clippy error + self.0 as *const u8 == other.0 as *const u8 + } +} fn null_unsafe_flow() -> UnsafeFlow { UnsafeFlow(ptr::null::()) } +#[allow(clippy::not_unsafe_ptr_arg_deref)] // It has an unsafe block inside pub fn mut_owned_flow_to_unsafe_flow(flow: *mut FlowRef) -> UnsafeFlow { unsafe { UnsafeFlow(&**flow) } } diff --git a/components/layout/query.rs b/components/layout/query.rs index 2bb03e2a5ca..4225c170b42 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -988,10 +988,10 @@ fn process_resolved_style_request_internal<'dom>( }, }; - let positioned = match style.get_box().position { - Position::Relative | Position::Sticky | Position::Fixed | Position::Absolute => true, - _ => false, - }; + let positioned = matches!( + style.get_box().position, + Position::Relative | Position::Sticky | Position::Fixed | Position::Absolute + ); //TODO: determine whether requested property applies to the element. // eg. width does not apply to non-replaced inline elements. diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index b641481a32a..cc6fd9e6316 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -86,6 +86,8 @@ pub fn build_display_list_for_subtree<'a>( let base = state.create_base_display_item( bounds, flow_root.as_block().fragment.node, + // The unique id is the same as the node id because this is the root fragment. + flow_root.as_block().fragment.node.id() as u64, None, DisplayListSection::BackgroundAndBorders, ); diff --git a/components/layout/table.rs b/components/layout/table.rs index d6ce1c9a2b0..1821769bc79 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -37,7 +37,7 @@ use crate::fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use crate::model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; use crate::table_cell::TableCellFlow; use crate::table_row::{ - self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderProvenance, TableRowFlow, + self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderFrom, TableRowFlow, TableRowSizeData, }; use crate::table_wrapper::TableLayout; @@ -339,11 +339,11 @@ impl Flow for TableFlow { Some(TableInlineCollapsedBorders { start: CollapsedBorder::inline_start( &self.block_flow.fragment.style, - CollapsedBorderProvenance::FromTable, + CollapsedBorderFrom::Table, ), end: CollapsedBorder::inline_end( &self.block_flow.fragment.style, - CollapsedBorderProvenance::FromTable, + CollapsedBorderFrom::Table, ), }) } else { @@ -354,7 +354,7 @@ impl Flow for TableFlow { let mut previous_collapsed_block_end_borders = PreviousBlockCollapsedBorders::FromTable(CollapsedBorder::block_start( &self.block_flow.fragment.style, - CollapsedBorderProvenance::FromTable, + CollapsedBorderFrom::Table, )); let mut first_row = true; let (border_padding, _) = self.block_flow.fragment.surrounding_intrinsic_inline_size(); @@ -381,7 +381,7 @@ impl Flow for TableFlow { ), None => NextBlockCollapsedBorders::FromTable(CollapsedBorder::block_end( &self.block_flow.fragment.style, - CollapsedBorderProvenance::FromTable, + CollapsedBorderFrom::Table, )), }; perform_border_collapse_for_row( diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index cf8c7d3f5bb..013702e9401 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -27,7 +27,7 @@ use crate::display_list::{ use crate::flow::{Flow, FlowClass, FlowFlags, GetBaseFlow, OpaqueFlow}; use crate::fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use crate::table::InternalTable; -use crate::table_row::{CollapsedBorder, CollapsedBorderProvenance}; +use crate::table_row::{CollapsedBorder, CollapsedBorderFrom}; use crate::{layout_debug, layout_debug_scope}; #[allow(unsafe_code)] @@ -406,19 +406,19 @@ impl CollapsedBordersForCell { } fn should_paint_inline_start_border(&self) -> bool { - self.inline_start_border.provenance != CollapsedBorderProvenance::FromPreviousTableCell + self.inline_start_border.provenance != CollapsedBorderFrom::PreviousTableCell } fn should_paint_inline_end_border(&self) -> bool { - self.inline_end_border.provenance != CollapsedBorderProvenance::FromNextTableCell + self.inline_end_border.provenance != CollapsedBorderFrom::NextTableCell } fn should_paint_block_start_border(&self) -> bool { - self.block_start_border.provenance != CollapsedBorderProvenance::FromPreviousTableCell + self.block_start_border.provenance != CollapsedBorderFrom::PreviousTableCell } fn should_paint_block_end_border(&self) -> bool { - self.block_end_border.provenance != CollapsedBorderProvenance::FromNextTableCell + self.block_end_border.provenance != CollapsedBorderFrom::NextTableCell } pub fn adjust_border_widths_for_painting(&self, border_widths: &mut LogicalMargin) { diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index ad99dd4b15a..fbc441055da 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -4,6 +4,8 @@ //! CSS table formatting contexts. +#![allow(clippy::too_many_arguments)] + use std::cmp::max; use std::fmt; use std::iter::{Enumerate, Peekable}; @@ -123,7 +125,7 @@ impl TableRowFlow { fn include_sizes_from_previous_rows( col: &mut usize, incoming_rowspan: &[u32], - incoming_rowspan_data: &mut Vec, + incoming_rowspan_data: &mut [Au], max_block_size: &mut Au, ) { while let Some(span) = incoming_rowspan.get(*col) { @@ -390,7 +392,7 @@ impl Flow for TableRowFlow { self.preliminary_collapsed_borders .reset(CollapsedBorder::inline_start( row_style, - CollapsedBorderProvenance::FromTableRow, + CollapsedBorderFrom::TableRow, )); { @@ -736,7 +738,7 @@ pub struct CollapsedBorder { /// The color of the border. pub color: Color, /// The type of item that this border comes from. - pub provenance: CollapsedBorderProvenance, + pub provenance: CollapsedBorderFrom, } impl Serialize for CollapsedBorder { @@ -753,14 +755,14 @@ impl Serialize for CollapsedBorder { // FromTableColumnGroup are unused #[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Serialize)] -pub enum CollapsedBorderProvenance { - FromPreviousTableCell = 6, - FromNextTableCell = 5, - FromTableRow = 4, - FromTableRowGroup = 3, - FromTableColumn = 2, - FromTableColumnGroup = 1, - FromTable = 0, +pub enum CollapsedBorderFrom { + PreviousTableCell = 6, + NextTableCell = 5, + TableRow = 4, + TableRowGroup = 3, + TableColumn = 2, + TableColumnGroup = 1, + Table = 0, } impl CollapsedBorder { @@ -770,13 +772,13 @@ impl CollapsedBorder { style: BorderStyle::None, width: Au(0), color: Color::transparent(), - provenance: CollapsedBorderProvenance::FromTable, + provenance: CollapsedBorderFrom::Table, } } /// Creates a collapsed border from the block-start border described in the given CSS style /// object. - fn top(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder { + fn top(css_style: &ComputedValues, provenance: CollapsedBorderFrom) -> CollapsedBorder { CollapsedBorder { style: css_style.get_border().border_top_style, width: css_style.get_border().border_top_width, @@ -787,7 +789,7 @@ impl CollapsedBorder { /// Creates a collapsed border style from the right border described in the given CSS style /// object. - fn right(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder { + fn right(css_style: &ComputedValues, provenance: CollapsedBorderFrom) -> CollapsedBorder { CollapsedBorder { style: css_style.get_border().border_right_style, width: css_style.get_border().border_right_width, @@ -798,10 +800,7 @@ impl CollapsedBorder { /// Creates a collapsed border style from the bottom border described in the given CSS style /// object. - fn bottom( - css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, - ) -> CollapsedBorder { + fn bottom(css_style: &ComputedValues, provenance: CollapsedBorderFrom) -> CollapsedBorder { CollapsedBorder { style: css_style.get_border().border_bottom_style, width: css_style.get_border().border_bottom_width, @@ -812,7 +811,7 @@ impl CollapsedBorder { /// Creates a collapsed border style from the left border described in the given CSS style /// object. - fn left(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder { + fn left(css_style: &ComputedValues, provenance: CollapsedBorderFrom) -> CollapsedBorder { CollapsedBorder { style: css_style.get_border().border_left_style, width: css_style.get_border().border_left_width, @@ -825,7 +824,7 @@ impl CollapsedBorder { fn from_side( side: PhysicalSide, css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, + provenance: CollapsedBorderFrom, ) -> CollapsedBorder { match side { PhysicalSide::Top => CollapsedBorder::top(css_style, provenance), @@ -839,7 +838,7 @@ impl CollapsedBorder { /// style object. pub fn inline_start( css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, + provenance: CollapsedBorderFrom, ) -> CollapsedBorder { CollapsedBorder::from_side( css_style.writing_mode.inline_start_physical_side(), @@ -852,7 +851,7 @@ impl CollapsedBorder { /// style object. pub fn inline_end( css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, + provenance: CollapsedBorderFrom, ) -> CollapsedBorder { CollapsedBorder::from_side( css_style.writing_mode.inline_end_physical_side(), @@ -865,7 +864,7 @@ impl CollapsedBorder { /// style object. pub fn block_start( css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, + provenance: CollapsedBorderFrom, ) -> CollapsedBorder { CollapsedBorder::from_side( css_style.writing_mode.block_start_physical_side(), @@ -878,7 +877,7 @@ impl CollapsedBorder { /// object. pub fn block_end( css_style: &ComputedValues, - provenance: CollapsedBorderProvenance, + provenance: CollapsedBorderFrom, ) -> CollapsedBorder { CollapsedBorder::from_side( css_style.writing_mode.block_end_physical_side(), @@ -1120,7 +1119,7 @@ fn perform_inline_direction_border_collapse_for_row( let first_inline_border = &mut preliminary_collapsed_borders.inline[0]; first_inline_border.combine(&CollapsedBorder::inline_start( &child_table_cell.block_flow.fragment.style, - CollapsedBorderProvenance::FromNextTableCell, + CollapsedBorderFrom::NextTableCell, )); } @@ -1128,7 +1127,7 @@ fn perform_inline_direction_border_collapse_for_row( child_index + 1, CollapsedBorder::inline_end( &child_table_cell.block_flow.fragment.style, - CollapsedBorderProvenance::FromPreviousTableCell, + CollapsedBorderFrom::PreviousTableCell, ), ); @@ -1136,7 +1135,7 @@ fn perform_inline_direction_border_collapse_for_row( let next_child_flow = next_child_flow.as_block(); inline_collapsed_border.combine(&CollapsedBorder::inline_start( &next_child_flow.fragment.style, - CollapsedBorderProvenance::FromNextTableCell, + CollapsedBorderFrom::NextTableCell, )) }; @@ -1145,28 +1144,28 @@ fn perform_inline_direction_border_collapse_for_row( if child_index + 1 == children_count { inline_collapsed_border.combine(&CollapsedBorder::inline_end( row_style, - CollapsedBorderProvenance::FromTableRow, + CollapsedBorderFrom::TableRow, )); } let mut block_start_border = CollapsedBorder::block_start( &child_table_cell.block_flow.fragment.style, - CollapsedBorderProvenance::FromNextTableCell, + CollapsedBorderFrom::NextTableCell, ); block_start_border.combine(&CollapsedBorder::block_start( row_style, - CollapsedBorderProvenance::FromTableRow, + CollapsedBorderFrom::TableRow, )); preliminary_collapsed_borders .block_start .push_or_set(child_index, block_start_border); let mut block_end_border = CollapsedBorder::block_end( &child_table_cell.block_flow.fragment.style, - CollapsedBorderProvenance::FromPreviousTableCell, + CollapsedBorderFrom::PreviousTableCell, ); block_end_border.combine(&CollapsedBorder::block_end( row_style, - CollapsedBorderProvenance::FromTableRow, + CollapsedBorderFrom::TableRow, )); preliminary_collapsed_borders diff --git a/components/layout/text.rs b/components/layout/text.rs index 0c6e8ecc424..4b62deeb7a3 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Text layout. +#![allow(clippy::too_many_arguments)] use std::borrow::ToOwned; use std::collections::LinkedList; @@ -10,12 +11,12 @@ use std::sync::Arc; use app_units::Au; use gfx::font::{self, FontMetrics, FontRef, RunMetrics, ShapingFlags, ShapingOptions}; +use gfx::font_cache_thread::FontIdentifier; use gfx::text::glyph::ByteIndex; use gfx::text::text_run::TextRun; use gfx::text::util::{self, CompressionMode}; use log::{debug, warn}; use range::Range; -use servo_atoms::Atom; use style::computed_values::text_rendering::T as TextRendering; use style::computed_values::white_space::T as WhiteSpace; use style::computed_values::word_break::T as WordBreak; @@ -483,10 +484,10 @@ impl TextRunScanner { SpecificFragmentInfo::ScannedText(new_text_fragment_info), ); - let is_last_mapping_of_this_old_fragment = match mappings.peek() { - Some(mapping) if mapping.old_fragment_index == logical_offset => false, - _ => true, - }; + let is_last_mapping_of_this_old_fragment = !matches!( + mappings.peek(), + Some(mapping) if mapping.old_fragment_index == logical_offset + ); if let Some(ref mut context) = new_fragment.inline_context { for node in &mut context.nodes { @@ -664,10 +665,10 @@ impl RunInfo { } fn has_font(&self, font: &Option) -> bool { - fn identifier_and_pt_size(font: &Option) -> Option<(Atom, Au)> { + fn identifier_and_pt_size(font: &Option) -> Option<(FontIdentifier, Au)> { font.as_ref().map(|font| { let font = font.borrow(); - (font.identifier(), font.descriptor.pt_size) + (font.identifier().clone(), font.descriptor.pt_size) }) } diff --git a/components/layout_2020/display_list/background.rs b/components/layout_2020/display_list/background.rs index ac8017f79d8..649662ab083 100644 --- a/components/layout_2020/display_list/background.rs +++ b/components/layout_2020/display_list/background.rs @@ -66,7 +66,7 @@ impl<'a> BackgroundPainter<'a> { // The 'backgound-clip' property maps directly to `clip_rect` in `CommonItemProperties`: let mut common = builder.common_properties(*painting_area, &fb.fragment.style); if let Some(clip_chain_id) = clip { - common.clip_id = wr::ClipId::ClipChain(clip_chain_id) + common.clip_chain_id = clip_chain_id; } (painting_area, common) } @@ -105,9 +105,9 @@ pub(super) fn layout_layer( Cover, } let size_contain_or_cover = |background_size| { - let mut tile_size = positioning_area.size; + let mut tile_size = positioning_area.size(); if let Some(intrinsic_ratio) = intrinsic.ratio { - let positioning_ratio = positioning_area.size.width / positioning_area.size.height; + let positioning_ratio = positioning_area.size().width / positioning_area.size().height; // Whether the tile width (as opposed to height) // is scaled to that of the positioning area let fit_width = match background_size { @@ -130,10 +130,10 @@ pub(super) fn layout_layer( Size::Cover => size_contain_or_cover(ContainOrCover::Cover), Size::ExplicitSize { width, height } => { let mut width = width.non_auto().map(|lp| { - lp.0.percentage_relative_to(Length::new(positioning_area.size.width)) + lp.0.percentage_relative_to(Length::new(positioning_area.size().width)) }); let mut height = height.non_auto().map(|lp| { - lp.0.percentage_relative_to(Length::new(positioning_area.size.height)) + lp.0.percentage_relative_to(Length::new(positioning_area.size().height)) }); if width.is_none() && height.is_none() { @@ -152,7 +152,7 @@ pub(super) fn layout_layer( intrinsic_height.into() } else { // Treated as 100% - Au::from_f32_px(positioning_area.size.height).into() + Au::from_f32_px(positioning_area.size().height).into() }; units::LayoutSize::new(w.px(), h.px()) }, @@ -163,7 +163,7 @@ pub(super) fn layout_layer( intrinsic_width.into() } else { // Treated as 100% - Au::from_f32_px(positioning_area.size.width).into() + Au::from_f32_px(positioning_area.size().width).into() }; units::LayoutSize::new(w.px(), h.px()) }, @@ -182,20 +182,20 @@ pub(super) fn layout_layer( &mut tile_size.width, repeat_x, get_cyclic(&b.background_position_x.0, layer_index), - painting_area.origin.x - positioning_area.origin.x, - painting_area.size.width, - positioning_area.size.width, + painting_area.min.x - positioning_area.min.x, + painting_area.size().width, + positioning_area.size().width, ); let result_y = layout_1d( &mut tile_size.height, repeat_y, get_cyclic(&b.background_position_y.0, layer_index), - painting_area.origin.y - positioning_area.origin.y, - painting_area.size.height, - positioning_area.size.height, + painting_area.min.y - positioning_area.min.y, + painting_area.size().height, + positioning_area.size().height, ); - let bounds = units::LayoutRect::new( - positioning_area.origin + Vector2D::new(result_x.bounds_origin, result_y.bounds_origin), + let bounds = units::LayoutRect::from_origin_and_size( + positioning_area.min + Vector2D::new(result_x.bounds_origin, result_y.bounds_origin), Size2D::new(result_x.bounds_size, result_y.bounds_size), ); let tile_spacing = units::LayoutSize::new(result_x.tile_spacing, result_y.tile_spacing); diff --git a/components/layout_2020/display_list/conversions.rs b/components/layout_2020/display_list/conversions.rs index e659a97f373..94e1418ba25 100644 --- a/components/layout_2020/display_list/conversions.rs +++ b/components/layout_2020/display_list/conversions.rs @@ -111,14 +111,20 @@ impl ToWebRender for PhysicalSize { impl ToWebRender for PhysicalRect { type Type = units::LayoutRect; fn to_webrender(&self) -> Self::Type { - units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender()) + units::LayoutRect::from_origin_and_size( + self.origin.to_webrender(), + self.size.to_webrender(), + ) } } impl ToWebRender for PhysicalRect { type Type = units::LayoutRect; fn to_webrender(&self) -> Self::Type { - units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender()) + units::LayoutRect::from_origin_and_size( + self.origin.to_webrender(), + self.size.to_webrender(), + ) } } diff --git a/components/layout_2020/display_list/gradient.rs b/components/layout_2020/display_list/gradient.rs index 7340a955ecf..f088ee91faa 100644 --- a/components/layout_2020/display_list/gradient.rs +++ b/components/layout_2020/display_list/gradient.rs @@ -5,9 +5,12 @@ use style::color::mix::ColorInterpolationMethod; use style::properties::ComputedValues; use style::values::computed::image::{EndingShape, Gradient, LineDirection}; -use style::values::computed::{Color, Length, LengthPercentage, Position}; +use style::values::computed::{ + Angle, AngleOrPercentage, Color, Length, LengthPercentage, Position, +}; use style::values::generics::image::{Circle, ColorStop, Ellipse, GradientItem, ShapeExtent}; use webrender_api::{self as wr, units}; +use wr::ColorF; pub(super) fn build( style: &ComputedValues, @@ -56,7 +59,26 @@ pub(super) fn build( layer, builder, ), - Gradient::Conic { .. } => unimplemented!(), + Gradient::Conic { + angle, + position, + color_interpolation_method, + items, + repeating, + } => build_conic( + style, + *angle, + position, + *color_interpolation_method, + items, + if *repeating { + wr::ExtendMode::Repeat + } else { + wr::ExtendMode::Clamp + }, + layer, + builder, + ), } } @@ -148,7 +170,9 @@ pub(super) fn build_linear( let start_point = center - half_gradient_line; let end_point = center + half_gradient_line; - let stops = fixup_stops(style, items, Length::new(gradient_line_length)); + let mut color_stops = + gradient_items_to_color_stops(style, items, Length::new(gradient_line_length)); + let stops = fixup_stops(&mut color_stops); let linear_gradient = builder .wr() .create_gradient(start_point, end_point, stops, extend_mode); @@ -162,6 +186,7 @@ pub(super) fn build_linear( } /// +#[allow(clippy::too_many_arguments)] pub(super) fn build_radial( style: &ComputedValues, items: &[GradientItem], @@ -249,7 +274,9 @@ pub(super) fn build_radial( // where the gradient line intersects the ending shape.” let gradient_line_length = radii.width; - let stops = fixup_stops(style, items, Length::new(gradient_line_length)); + let mut color_stops = + gradient_items_to_color_stops(style, items, Length::new(gradient_line_length)); + let stops = fixup_stops(&mut color_stops); let radial_gradient = builder .wr() .create_radial_gradient(center, radii, stops, extend_mode); @@ -262,12 +289,48 @@ pub(super) fn build_radial( ) } -/// -fn fixup_stops( +/// +#[allow(clippy::too_many_arguments)] +fn build_conic( style: &ComputedValues, - items: &[GradientItem], - gradient_line_length: Length, -) -> Vec { + angle: Angle, + center: &Position, + _color_interpolation_method: ColorInterpolationMethod, + items: &[GradientItem], + extend_mode: wr::ExtendMode, + layer: &super::background::BackgroundLayer, + builder: &mut super::DisplayListBuilder<'_>, +) { + let gradient_box = layer.tile_size; + let center = units::LayoutPoint::new( + center + .horizontal + .percentage_relative_to(Length::new(gradient_box.width)) + .px(), + center + .vertical + .percentage_relative_to(Length::new(gradient_box.height)) + .px(), + ); + let mut color_stops = conic_gradient_items_to_color_stops(style, items); + let stops = fixup_stops(&mut color_stops); + let conic_gradient = + builder + .wr() + .create_conic_gradient(center, angle.radians(), stops, extend_mode); + builder.wr().push_conic_gradient( + &layer.common, + layer.bounds, + conic_gradient, + layer.tile_size, + layer.tile_spacing, + ) +} + +fn conic_gradient_items_to_color_stops( + style: &ComputedValues, + items: &[GradientItem], +) -> Vec> { // Remove color transititon hints, which are not supported yet. // https://drafts.csswg.org/css-images-4/#color-transition-hint // @@ -278,28 +341,71 @@ fn fixup_stops( // Either way, the best outcome is to add support. // Gecko does so by approximating the non-linear interpolation // by up to 10 piece-wise linear segments (9 intermediate color stops) - let mut stops = Vec::with_capacity(items.len()); - for item in items { - match item { - GradientItem::SimpleColorStop(color) => stops.push(ColorStop { - color: super::rgba(style.resolve_color(color.clone())), - position: None, - }), - GradientItem::ComplexColorStop { color, position } => stops.push(ColorStop { - color: super::rgba(style.resolve_color(color.clone())), - position: Some(if gradient_line_length.px() == 0. { - 0. - } else { - position.percentage_relative_to(gradient_line_length).px() / - gradient_line_length.px() + items + .iter() + .filter_map(|item| { + match item { + GradientItem::SimpleColorStop(color) => Some(ColorStop { + color: super::rgba(style.resolve_color(color.clone())), + position: None, + }), + GradientItem::ComplexColorStop { color, position } => Some(ColorStop { + color: super::rgba(style.resolve_color(color.clone())), + position: match position { + AngleOrPercentage::Percentage(percentage) => Some(percentage.0), + AngleOrPercentage::Angle(angle) => Some(angle.degrees() / 360.), + }, }), - }), - GradientItem::InterpolationHint(_) => { // FIXME: approximate like in: // https://searchfox.org/mozilla-central/rev/f98dad153b59a985efd4505912588d4651033395/layout/painting/nsCSSRenderingGradients.cpp#315-391 - }, - } - } + GradientItem::InterpolationHint(_) => None, + } + }) + .collect() +} + +fn gradient_items_to_color_stops( + style: &ComputedValues, + items: &[GradientItem], + gradient_line_length: Length, +) -> Vec> { + // Remove color transititon hints, which are not supported yet. + // https://drafts.csswg.org/css-images-4/#color-transition-hint + // + // This gives an approximation of the gradient that might be visibly wrong, + // but maybe better than not parsing that value at all? + // It’s debatble whether that’s better or worse + // than not parsing and allowing authors to set a fallback. + // Either way, the best outcome is to add support. + // Gecko does so by approximating the non-linear interpolation + // by up to 10 piece-wise linear segments (9 intermediate color stops) + items + .iter() + .filter_map(|item| { + match item { + GradientItem::SimpleColorStop(color) => Some(ColorStop { + color: super::rgba(style.resolve_color(color.clone())), + position: None, + }), + GradientItem::ComplexColorStop { color, position } => Some(ColorStop { + color: super::rgba(style.resolve_color(color.clone())), + position: Some(if gradient_line_length.px() == 0. { + 0. + } else { + position.percentage_relative_to(gradient_line_length).px() / + gradient_line_length.px() + }), + }), + // FIXME: approximate like in: + // https://searchfox.org/mozilla-central/rev/f98dad153b59a985efd4505912588d4651033395/layout/painting/nsCSSRenderingGradients.cpp#315-391 + GradientItem::InterpolationHint(_) => None, + } + }) + .collect() +} + +/// +fn fixup_stops(stops: &mut Vec>) -> Vec { assert!(stops.len() >= 2); // https://drafts.csswg.org/css-images-4/#color-stop-fixup diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index 5902baf63c0..189ae56c541 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -12,7 +12,7 @@ use gfx::text::glyph::GlyphStore; use gfx_traits::WebRenderEpochToU16; use msg::constellation_msg::BrowsingContextId; use net_traits::image_cache::UsePlaceholder; -use script_traits::compositor::{CompositorDisplayListInfo, ScrollTreeNodeId}; +use script_traits::compositor::{CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId}; use servo_geometry::MaxRect; use style::color::{AbsoluteColor, ColorSpace}; use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle; @@ -23,14 +23,15 @@ use style::values::computed::{BorderStyle, Color, Length, LengthPercentage, Outl use style::values::specified::text::TextDecorationLine; use style::values::specified::ui::CursorKind; use style_traits::CSSPixel; -use webrender_api::{self as wr, units, ClipChainId, ClipId, CommonItemProperties}; +use webrender_api::{self as wr, units, BoxShadowClipMode, ClipChainId}; use wr::units::LayoutVector2D; -use wr::BoxShadowClipMode; use crate::context::LayoutContext; use crate::display_list::conversions::ToWebRender; use crate::display_list::stacking_context::StackingContextSection; -use crate::fragment_tree::{BoxFragment, Fragment, FragmentTree, Tag, TextFragment}; +use crate::fragment_tree::{ + BackgroundMode, BoxFragment, Fragment, FragmentTree, Tag, TextFragment, +}; use crate::geom::{LogicalRect, PhysicalPoint, PhysicalRect}; use crate::replaced::IntrinsicSizes; use crate::style_ext::ComputedValuesExt; @@ -67,6 +68,11 @@ pub struct DisplayList { /// data structure that the compositor uses to map hit tests to information /// about the item hit. pub compositor_info: CompositorDisplayListInfo, + + /// A count of the number of SpatialTree nodes pushed to the WebRender display + /// list. This is merely to ensure that the currently-unused SpatialTreeItemKey + /// produced for every SpatialTree node is unique. + pub spatial_tree_count: u64, } impl DisplayList { @@ -77,6 +83,7 @@ impl DisplayList { content_size: units::LayoutSize, pipeline_id: wr::PipelineId, epoch: wr::Epoch, + root_scroll_sensitivity: ScrollSensitivity, ) -> Self { Self { wr: wr::DisplayListBuilder::new(pipeline_id), @@ -85,21 +92,39 @@ impl DisplayList { content_size, pipeline_id, epoch, + root_scroll_sensitivity, ), + spatial_tree_count: 0, } } + + pub fn define_clip_chain(&mut self, parent: ClipChainId, clips: I) -> ClipChainId + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone, + { + // WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be + // used for primitives, but `None` is used for stacking contexts and clip chains. We convert + // to the `Option` representation here. Just passing Some(ClipChainId::INVALID) + // leads to a crash. + let parent = match parent { + ClipChainId::INVALID => None, + parent => Some(parent), + }; + self.wr.define_clip_chain(parent, clips) + } } pub(crate) struct DisplayListBuilder<'a> { /// The current [ScrollTreeNodeId] for this [DisplayListBuilder]. This /// allows only passing the builder instead passing the containing - /// [stacking_context::StackingContextFragment] as an argument to display + /// [stacking_context::StackingContextContent::Fragment] as an argument to display /// list building functions. current_scroll_node_id: ScrollTreeNodeId, /// The current [wr::ClipId] for this [DisplayListBuilder]. This allows /// only passing the builder instead passing the containing - /// [stacking_context::StackingContextFragment] as an argument to display + /// [stacking_context::StackingContextContent::Fragment] as an argument to display /// list building functions. current_clip_chain_id: ClipChainId, @@ -135,7 +160,7 @@ impl DisplayList { ) -> (FnvHashMap>, bool) { let mut builder = DisplayListBuilder { current_scroll_node_id: self.compositor_info.root_reference_frame_id, - current_clip_chain_id: ClipChainId(0, self.compositor_info.pipeline_id), + current_clip_chain_id: ClipChainId::INVALID, element_for_canvas_background: fragment_tree.canvas_background.from_element, is_contentful: false, context, @@ -163,7 +188,7 @@ impl<'a> DisplayListBuilder<'a> { wr::CommonItemProperties { clip_rect, spatial_id: self.current_scroll_node_id.spatial_id, - clip_id: ClipId::ClipChain(self.current_clip_chain_id), + clip_chain_id: self.current_clip_chain_id, flags: style.get_webrender_primitive_flags(), } } @@ -264,7 +289,7 @@ impl Fragment { common.clip_rect, &wr::SpaceAndClipInfo { spatial_id: common.spatial_id, - clip_id: common.clip_id, + clip_chain_id: common.clip_chain_id, }, iframe.pipeline_id.to_webrender(), true, @@ -300,12 +325,10 @@ impl Fragment { let clip_chain_id = builder.current_clip_chain_id; let spatial_id = builder.current_scroll_node_id.spatial_id; builder.wr().push_hit_test( - &CommonItemProperties { - clip_rect: rect.to_webrender(), - clip_id: ClipId::ClipChain(clip_chain_id), - spatial_id, - flags: style.get_webrender_primitive_flags(), - }, + rect.to_webrender(), + clip_chain_id, + spatial_id, + style.get_webrender_primitive_flags(), hit_info, ); } @@ -401,7 +424,7 @@ impl Fragment { color: &AbsoluteColor, ) { let rect = rect.to_webrender(); - let wavy_line_thickness = (0.33 * rect.size.height).ceil(); + let wavy_line_thickness = (0.33 * rect.size().height).ceil(); let text_decoration_color = fragment .parent_style .clone_text_decoration_color() @@ -448,8 +471,8 @@ impl<'a> BuilderForBoxFragment<'a> { }; let corner = |corner: &style::values::computed::BorderCornerRadius| { Size2D::new( - resolve(&corner.0.width.0, border_rect.size.width), - resolve(&corner.0.height.0, border_rect.size.height), + resolve(&corner.0.width.0, border_rect.size().width), + resolve(&corner.0.height.0, border_rect.size().height), ) }; let b = fragment.style.get_border(); @@ -573,9 +596,15 @@ impl<'a> BuilderForBoxFragment<'a> { let mut common = builder.common_properties(self.border_rect, &self.fragment.style); if let Some(clip_chain_id) = self.border_edge_clip(builder) { - common.clip_id = ClipId::ClipChain(clip_chain_id); + common.clip_chain_id = clip_chain_id; } - builder.wr().push_hit_test(&common, hit_info); + builder.wr().push_hit_test( + common.clip_rect, + common.clip_chain_id, + common.spatial_id, + common.flags, + hit_info, + ); } fn build_background_for_painter( @@ -609,19 +638,29 @@ impl<'a> BuilderForBoxFragment<'a> { return; } - for extra_background in self.fragment.extra_backgrounds.iter() { - let positioning_area: LogicalRect = extra_background.rect.clone().into(); - let painter = BackgroundPainter { - style: &extra_background.style, - painting_area_override: None, - positioning_area_override: Some( - positioning_area - .to_physical(self.fragment.style.writing_mode, self.containing_block) - .translate(self.containing_block.origin.to_vector()) - .to_webrender(), - ), - }; - self.build_background_for_painter(builder, &painter); + // If this BoxFragment does not paint a background, do nothing. + if let BackgroundMode::None = self.fragment.background_mode { + return; + } + + // Paint all extra backgrounds for this BoxFragment. These are painted first, as that's + // the order that they are expected to be painted for table cells (where this feature + // is used). + if let BackgroundMode::Extra(ref extra_backgrounds) = self.fragment.background_mode { + for extra_background in extra_backgrounds { + let positioning_area: LogicalRect = extra_background.rect.clone().into(); + let painter = BackgroundPainter { + style: &extra_background.style, + painting_area_override: None, + positioning_area_override: Some( + positioning_area + .to_physical(self.fragment.style.writing_mode, self.containing_block) + .translate(self.containing_block.origin.to_vector()) + .to_webrender(), + ), + }; + self.build_background_for_painter(builder, &painter); + } } let painter = BackgroundPainter { @@ -997,13 +1036,10 @@ fn clip_for_radii( if radii.is_zero() { None } else { - let clip_chain_id = builder.current_clip_chain_id; - let parent_space_and_clip = wr::SpaceAndClipInfo { - spatial_id: builder.current_scroll_node_id.spatial_id, - clip_id: ClipId::ClipChain(clip_chain_id), - }; + let spatial_id = builder.current_scroll_node_id.spatial_id; + let parent_clip_chain_id = builder.current_clip_chain_id; let new_clip_id = builder.wr().define_clip_rounded_rect( - &parent_space_and_clip, + spatial_id, wr::ComplexClipRegion { rect, radii, @@ -1012,8 +1048,8 @@ fn clip_for_radii( ); Some( builder - .wr() - .define_clip_chain(Some(clip_chain_id), [new_clip_id]), + .display_list + .define_clip_chain(parent_clip_chain_id, [new_clip_id]), ) } } diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index 47819d0bd10..bdca1e5d77a 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -9,7 +9,7 @@ use euclid::default::Rect; use euclid::SideOffsets2D; use gfx_traits::print_tree::PrintTree; use log::warn; -use script_traits::compositor::{ScrollTreeNodeId, ScrollableNodeInfo}; +use script_traits::compositor::{ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo}; use servo_arc::Arc as ServoArc; use servo_config::opts::DebugOptions; use style::computed_values::float::T as ComputedFloat; @@ -23,16 +23,15 @@ use style::values::generics::transform; use style::values::specified::box_::DisplayOutside; use webrender_api as wr; use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D}; -use webrender_api::ScrollSensitivity; use wr::units::{LayoutPixel, LayoutSize}; -use wr::StickyOffsetBounds; +use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds}; use super::DisplayList; use crate::cell::ArcRefCell; use crate::display_list::conversions::{FilterToWebRender, ToWebRender}; use crate::display_list::DisplayListBuilder; use crate::fragment_tree::{ - BoxFragment, ContainingBlockManager, Fragment, FragmentTree, PositioningFragment, + BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree, PositioningFragment, }; use crate::geom::{PhysicalRect, PhysicalSides}; use crate::style_ext::ComputedValuesExt; @@ -90,26 +89,30 @@ pub(crate) enum StackingContextSection { } impl DisplayList { + /// Produce a new SpatialTreeItemKey. This is currently unused by WebRender, + /// but has to be unique to the entire scene. + fn get_next_spatial_tree_item_key(&mut self) -> SpatialTreeItemKey { + self.spatial_tree_count += 1; + let pipeline_tag = (self.wr.pipeline_id.0 as u64) << 32 | self.wr.pipeline_id.1 as u64; + SpatialTreeItemKey::new(pipeline_tag, self.spatial_tree_count) + } + pub fn build_stacking_context_tree( &mut self, fragment_tree: &FragmentTree, debug: &DebugOptions, ) -> StackingContext { - let root_clip_chain_id = self - .wr - .define_clip_chain(None, [wr::ClipId::root(self.wr.pipeline_id)]); - let cb_for_non_fixed_descendants = ContainingBlock::new( fragment_tree.initial_containing_block, self.compositor_info.root_scroll_node_id, Some(self.compositor_info.viewport_size), - root_clip_chain_id, + ClipChainId::INVALID, ); let cb_for_fixed_descendants = ContainingBlock::new( fragment_tree.initial_containing_block, self.compositor_info.root_reference_frame_id, None, - root_clip_chain_id, + ClipChainId::INVALID, ); // We need to specify all three containing blocks here, because absolute @@ -146,12 +149,14 @@ impl DisplayList { transform: wr::PropertyBinding, kind: wr::ReferenceFrameKind, ) -> ScrollTreeNodeId { + let spatial_tree_item_key = self.get_next_spatial_tree_item_key(); let new_spatial_id = self.wr.push_reference_frame( origin, parent_scroll_node_id.spatial_id, transform_style, transform, kind, + spatial_tree_item_key, ); self.compositor_info.scroll_tree.add_scroll_tree_node( Some(parent_scroll_node_id), @@ -173,36 +178,29 @@ impl DisplayList { clip_rect: LayoutRect, scroll_sensitivity: ScrollSensitivity, ) -> (ScrollTreeNodeId, wr::ClipChainId) { - let parent_space_and_clip_info = wr::SpaceAndClipInfo { - spatial_id: parent_scroll_node_id.spatial_id, - clip_id: wr::ClipId::root(self.wr.pipeline_id), - }; let new_clip_id = self .wr - .define_clip_rect(&parent_space_and_clip_info, clip_rect); + .define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect); + let new_clip_chain_id = self.define_clip_chain(*parent_clip_chain_id, [new_clip_id]); + let spatial_tree_item_key = self.get_next_spatial_tree_item_key(); - let new_clip_chain_id = self - .wr - .define_clip_chain(Some(*parent_clip_chain_id), [new_clip_id]); - - let new_spatial_id = self - .wr - .define_scroll_frame( - &parent_space_and_clip_info, - external_id, - content_rect, - clip_rect, - scroll_sensitivity, - LayoutVector2D::zero(), /* external_scroll_offset */ - ) - .spatial_id; + let new_spatial_id = self.wr.define_scroll_frame( + parent_scroll_node_id.spatial_id, + external_id, + content_rect, + clip_rect, + LayoutVector2D::zero(), /* external_scroll_offset */ + 0, /* scroll_offset_generation */ + wr::HasScrollLinkedEffect::No, + spatial_tree_item_key, + ); let new_scroll_node_id = self.compositor_info.scroll_tree.add_scroll_tree_node( Some(parent_scroll_node_id), new_spatial_id, Some(ScrollableNodeInfo { external_id, - scrollable_size: content_rect.size - clip_rect.size, + scrollable_size: content_rect.size() - clip_rect.size(), scroll_sensitivity, offset: LayoutVector2D::zero(), }), @@ -218,13 +216,15 @@ impl DisplayList { vertical_offset_bounds: StickyOffsetBounds, horizontal_offset_bounds: StickyOffsetBounds, ) -> ScrollTreeNodeId { + let spatial_tree_item_key = self.get_next_spatial_tree_item_key(); let new_spatial_id = self.wr.define_sticky_frame( parent_scroll_node_id.spatial_id, frame_rect, margins, vertical_offset_bounds, horizontal_offset_bounds, - LayoutVector2D::zero(), + LayoutVector2D::zero(), /* previously_applied_offset */ + spatial_tree_item_key, ); self.compositor_info.scroll_tree.add_scroll_tree_node( Some(parent_scroll_node_id), @@ -368,10 +368,18 @@ impl StackingContext { fn create_descendant( &self, spatial_id: wr::SpatialId, - clip_chain_id: Option, + clip_chain_id: wr::ClipChainId, initializing_fragment_style: ServoArc, context_type: StackingContextType, ) -> Self { + // WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be + // used for primitives, but `None` is used for stacking contexts and clip chains. We convert + // to the `Option` representation here. Just passing Some(ClipChainId::INVALID) + // leads to a crash. + let clip_chain_id: Option = match clip_chain_id { + ClipChainId::INVALID => None, + clip_chain_id => Some(clip_chain_id), + }; Self { spatial_id, clip_chain_id, @@ -430,11 +438,11 @@ impl StackingContext { debug_assert!(self .real_stacking_contexts_and_positioned_stacking_containers .iter() - .all(|c| match c.context_type { + .all(|c| matches!( + c.context_type, StackingContextType::RealStackingContext | - StackingContextType::PositionedStackingContainer => true, - _ => false, - })); + StackingContextType::PositionedStackingContainer + ))); debug_assert!(self .float_stacking_containers .iter() @@ -471,8 +479,6 @@ impl StackingContext { return false; } - let clip_id = self.clip_chain_id.map(wr::ClipId::ClipChain); - // Create the filter pipeline. let current_color = style.clone_color(); let mut filters: Vec = effects @@ -498,7 +504,7 @@ impl StackingContext { LayoutPoint::zero(), // origin self.spatial_id, style.get_webrender_primitive_flags(), - clip_id, + self.clip_chain_id, style.get_used_transform_style().to_webrender(), effects.mix_blend_mode.to_webrender(), &filters, @@ -621,13 +627,13 @@ impl StackingContext { if let Some(reference_frame_data) = box_fragment.reference_frame_data_if_necessary(containing_block_rect) { - painting_area.origin -= reference_frame_data.origin.to_webrender().to_vector(); + painting_area.min -= reference_frame_data.origin.to_webrender().to_vector(); if let Some(transformed) = reference_frame_data .transform .inverse() - .and_then(|inversed| inversed.outer_transformed_rect(&painting_area)) + .and_then(|inversed| inversed.outer_transformed_rect(&painting_area.to_rect())) { - painting_area = transformed + painting_area = transformed.to_box2d(); } else { // The desired rect cannot be represented, so skip painting this background-image return; @@ -1038,7 +1044,7 @@ impl BoxFragment { let mut child_stacking_context = parent_stacking_context.create_descendant( containing_block.scroll_node_id.spatial_id, - Some(containing_block.clip_chain_id), + containing_block.clip_chain_id, self.style.clone(), context_type, ); @@ -1219,19 +1225,10 @@ impl BoxFragment { .translate(containing_block_rect.origin.to_vector()) .to_webrender(); - let parent_space_and_clip = &wr::SpaceAndClipInfo { - spatial_id: parent_scroll_node_id.spatial_id, - clip_id: wr::ClipId::root(display_list.wr.pipeline_id), - }; - let clip_id = display_list .wr - .define_clip_rect(parent_space_and_clip, clip_rect); - Some( - display_list - .wr - .define_clip_chain(Some(*parent_clip_chain_id), [clip_id]), - ) + .define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect); + Some(display_list.define_clip_chain(*parent_clip_chain_id, [clip_id])) } fn build_scroll_frame_if_necessary( @@ -1247,6 +1244,24 @@ impl BoxFragment { return None; } + // From https://drafts.csswg.org/css-overflow/#propdef-overflow: + // > UAs must apply the overflow-* values set on the root element to the viewport when the + // > root element’s display value is not none. However, when the root element is an [HTML] + // > html element (including XML syntax for HTML) whose overflow value is visible (in both + // > axes), and that element has as a child a body element whose display value is also not + // > none, user agents must instead apply the overflow-* values of the first such child + // > element to the viewport. The element from which the value is propagated must then have a + // > used overflow value of visible. + // + // TODO: This should only happen when the `display` value is actually propagated. + if self + .base + .flags + .contains(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT) + { + return None; + } + let tag = self.base.tag?; let external_id = wr::ExternalScrollId( tag.to_display_list_fragment_id(), @@ -1276,7 +1291,7 @@ impl BoxFragment { sensitivity, ); - Some((scroll_tree_node_id, clip_chain_id, padding_rect.size)) + Some((scroll_tree_node_id, clip_chain_id, padding_rect.size())) } fn build_sticky_frame_if_necessary( @@ -1343,12 +1358,12 @@ impl BoxFragment { // This is the minimum negative offset and then the maximum positive offset. We just // specify every edge, but if the corresponding margin is None, that offset has no effect. let vertical_offset_bounds = wr::StickyOffsetBounds::new( - containing_block_rect.min_y() - frame_rect.min_y(), - containing_block_rect.max_y() - frame_rect.max_y(), + containing_block_rect.min.y - frame_rect.min.y, + containing_block_rect.max.y - frame_rect.max.y, ); let horizontal_offset_bounds = wr::StickyOffsetBounds::new( - containing_block_rect.min_x() - frame_rect.min_x(), - containing_block_rect.max_x() - frame_rect.max_x(), + containing_block_rect.min.x - frame_rect.min.x, + containing_block_rect.max.x - frame_rect.max.x, ); let margins = SideOffsets2D::new( @@ -1398,6 +1413,7 @@ impl BoxFragment { wr::ReferenceFrameKind::Transform { is_2d_scale_translation: false, should_snap: false, + paired_with_perspective: false, }, ), (Some(transform), Some(perspective)) => ( diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index c1226d7d1d8..b00108a2b9a 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use html5ever::{local_name, LocalName}; +use log::warn; use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use servo_arc::Arc as ServoArc; use style::properties::ComputedValues; @@ -27,7 +28,7 @@ pub(crate) enum WhichPseudoElement { /// avoid having to repeat the same arguments in argument lists. #[derive(Clone)] pub(crate) struct NodeAndStyleInfo { - pub node: Node, + pub node: Option, pub pseudo_element_type: Option, pub style: ServoArc, } @@ -39,7 +40,7 @@ impl NodeAndStyleInfo { style: ServoArc, ) -> Self { Self { - node, + node: Some(node), pseudo_element_type: Some(pseudo_element_type), style, } @@ -47,7 +48,7 @@ impl NodeAndStyleInfo { pub(crate) fn new(node: Node, style: ServoArc) -> Self { Self { - node, + node: Some(node), pseudo_element_type: None, style, } @@ -55,6 +56,14 @@ impl NodeAndStyleInfo { } impl NodeAndStyleInfo { + pub(crate) fn new_anonymous(&self, style: ServoArc) -> Self { + Self { + node: None, + pseudo_element_type: self.pseudo_element_type, + style, + } + } + pub(crate) fn new_replacing_style(&self, style: ServoArc) -> Self { Self { node: self.node.clone(), @@ -69,12 +78,17 @@ where Node: NodeExt<'dom>, { fn from(info: &NodeAndStyleInfo) -> Self { + let node = match info.node { + Some(node) => node, + None => return Self::anonymous(), + }; + let pseudo = info.pseudo_element_type.map(|pseudo| match pseudo { WhichPseudoElement::Before => PseudoElement::Before, WhichPseudoElement::After => PseudoElement::After, }); - let threadsafe_node = info.node.to_threadsafe(); + let threadsafe_node = node.to_threadsafe(); let flags = match threadsafe_node.as_element() { Some(element) if element.is_body_element_of_html_element_root() => { FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT @@ -86,7 +100,7 @@ where }; Self { - tag: Tag::new_pseudo(threadsafe_node.opaque(), pseudo), + tag: Some(Tag::new_pseudo(threadsafe_node.opaque(), pseudo)), flags, } } @@ -302,8 +316,15 @@ impl NonReplacedContents { ) where Node: NodeExt<'dom>, { + let node = match info.node { + Some(node) => node, + None => { + warn!("Tried to traverse an anonymous node!"); + return; + }, + }; match self { - NonReplacedContents::OfElement => traverse_children_of(info.node, context, handler), + NonReplacedContents::OfElement => traverse_children_of(node, context, handler), NonReplacedContents::OfPseudoElement(items) => { traverse_pseudo_element_contents(info, context, handler, items) }, diff --git a/components/layout_2020/flexbox/construct.rs b/components/layout_2020/flexbox/construct.rs index b5aa9b34c47..065e03989d3 100644 --- a/components/layout_2020/flexbox/construct.rs +++ b/components/layout_2020/flexbox/construct.rs @@ -160,9 +160,7 @@ where self.context, self.text_decoration_line, ); - let info = &self - .info - .new_replacing_style(anonymous_style.clone().unwrap()); + let info = &self.info.new_anonymous(anonymous_style.clone().unwrap()); IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext { base_fragment_info: info.into(), style: info.style.clone(), diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index c379dc451fc..65d1800a419 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -67,7 +67,7 @@ struct FlexItem<'a> { /// Sum of padding, border, and margin (with `auto` assumed to be zero) in each axis. /// This is the difference between an outer and inner size. - pbm_auto_is_zero: FlexRelativeVec2, + pbm_auto_is_zero: FlexRelativeVec2, /// flex_base_size: Length, @@ -509,7 +509,7 @@ impl<'a> FlexItem<'a> { inline: min_size.inline.auto_is(automatic_min_size), block: min_size.block.auto_is(Length::zero), }; - let margin_auto_is_zero = pbm.margin.auto_is(Length::zero); + let margin_auto_is_zero = pbm.margin.auto_is(Au::zero); let content_box_size = flex_context.vec2_to_flex_relative(content_box_size); let content_max_size = flex_context.vec2_to_flex_relative(max_size); @@ -519,8 +519,8 @@ impl<'a> FlexItem<'a> { let border = flex_context.sides_to_flex_relative(pbm.border); let padding_border = padding.sum_by_axis() + border.sum_by_axis(); let pbm_auto_is_zero = FlexRelativeVec2 { - main: padding_border.main.into(), - cross: padding_border.cross.into(), + main: padding_border.main, + cross: padding_border.cross, } + margin_auto_is_zero.sum_by_axis(); let align_self = flex_context.align_for(&box_.style().clone_align_self()); @@ -535,9 +535,7 @@ impl<'a> FlexItem<'a> { let hypothetical_main_size = flex_base_size.clamp_between_extremums(content_min_size.main, content_max_size.main); - let margin: FlexRelativeSides = flex_context - .sides_to_flex_relative(pbm.margin) - .map(|v| v.map(|v| v.into())); + let margin: FlexRelativeSides = flex_context.sides_to_flex_relative(pbm.margin); Self { box_, @@ -652,7 +650,7 @@ fn collect_flex_lines<'items, LineResult>( let line = FlexLine { outer_hypothetical_main_sizes_sum: items .iter() - .map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main) + .map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main.into()) .sum(), items, }; @@ -663,7 +661,7 @@ fn collect_flex_lines<'items, LineResult>( let mut line_so_far_is_empty = true; let mut index = 0; while let Some(item) = items.get(index) { - let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main; + let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main.into(); let line_size_would_be = line_size_so_far + item_size; let item_fits = line_size_would_be <= container_main_size; if item_fits || line_so_far_is_empty { @@ -739,7 +737,7 @@ impl FlexLine<'_> { item.content_box_size.cross.is_auto() && !(item.margin.cross_start.is_auto() || item.margin.cross_end.is_auto()) { - (line_cross_size - item.pbm_auto_is_zero.cross).clamp_between_extremums( + (line_cross_size - item.pbm_auto_is_zero.cross.into()).clamp_between_extremums( item.content_min_size.cross, item.content_max_size.cross, ) @@ -922,11 +920,12 @@ impl FlexLine<'_> { .map(|((item, target_main_size), frozen)| { item.pbm_auto_is_zero.main + if frozen.get() { - target_main_size.get() + target_main_size.get().into() } else { - item.flex_base_size + item.flex_base_size.into() } }) + .map(|t| t.into()) .sum() }; // https://drafts.csswg.org/css-flexbox/#initial-free-space @@ -1109,7 +1108,7 @@ impl<'a> FlexItem<'a> { flex_context.layout_context, &mut positioning_context, &item_as_containing_block, - &flex_context.containing_block, + flex_context.containing_block, ); let hypothetical_cross_size = self @@ -1155,7 +1154,7 @@ impl<'items> FlexLine<'items> { .iter() .zip(&*self.items) .map(|(item_result, item)| { - item_result.hypothetical_cross_size + item.pbm_auto_is_zero.cross + item_result.hypothetical_cross_size + item.pbm_auto_is_zero.cross.into() }); // FIXME: add support for `align-self: baseline` // and computing the baseline of flex items. @@ -1256,8 +1255,8 @@ impl FlexItem<'_> { (AuOrAuto::Auto, AuOrAuto::Auto) => 2., _ => 1., }; - let outer_size = self.pbm_auto_is_zero.cross + item_cross_content_size; - let available = line_cross_size - outer_size; + let outer_size = self.pbm_auto_is_zero.cross + item_cross_content_size.into(); + let available = line_cross_size - outer_size.into(); let start; let end; if available > Length::zero() { @@ -1310,11 +1309,11 @@ impl FlexItem<'_> { match self.align_self { AlignItems::Stretch | AlignItems::FlexStart => Length::zero(), AlignItems::FlexEnd => { - let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross; + let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross.into(); line_cross_size - margin_box_cross }, AlignItems::Center => { - let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross; + let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross.into(); (line_cross_size - margin_box_cross) / 2. }, // FIXME: handle baseline alignment diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 1a512910374..d61804751b0 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -54,7 +54,7 @@ impl BlockFormattingContext { } } - pub fn construct_for_text_runs<'dom>( + pub fn construct_for_text_runs( runs: impl Iterator, layout_context: &LayoutContext, text_decoration_line: TextDecorationLine, @@ -317,7 +317,8 @@ where self.current_inline_level_boxes() .push(ArcRefCell::new(InlineLevelBox::Atomic(ifc))); } else { - let anonymous_info = self.info.new_replacing_style(ifc.style().clone()); + self.end_ongoing_inline_formatting_context(); + let anonymous_info = self.info.new_anonymous(ifc.style().clone()); let table_block = ArcRefCell::new(BlockLevelBox::Independent(ifc)); self.block_level_boxes.push(BlockLevelJob { info: anonymous_info, @@ -409,15 +410,11 @@ where // collecting all Cow strings into a vector and passing them along to text breaking // and shaping during final InlineFormattingContext construction. let inlines = self.current_inline_level_boxes(); - match inlines.last_mut().map(|last| last.borrow_mut()) { - Some(mut last_box) => match *last_box { - InlineLevelBox::TextRun(ref mut text_run) => { - text_run.text.push_str(&input); - return; - }, - _ => {}, - }, - _ => {}, + if let Some(mut last_box) = inlines.last_mut().map(|last| last.borrow_mut()) { + if let InlineLevelBox::TextRun(ref mut text_run) = *last_box { + text_run.text.push_str(&input); + return; + } } inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun::new( @@ -490,6 +487,8 @@ where .unwrap() .traverse(self.context, info, self); + self.finish_anonymous_table_if_needed(); + let mut inline_box = self .ongoing_inline_boxes_stack .pop() @@ -690,7 +689,7 @@ where ); std::mem::swap(&mut self.ongoing_inline_formatting_context, &mut ifc); - let info = self.info.new_replacing_style(anonymous_style.clone()); + let info = self.info.new_anonymous(anonymous_style.clone()); self.block_level_boxes.push(BlockLevelJob { info, // FIXME(nox): We should be storing this somewhere. diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index fa40ae1bb22..ca212e4202b 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -113,9 +113,9 @@ impl<'a> PlacementAmongFloats<'a> { (current_bands, next_band) }; let min_inline_start = float_context.containing_block_info.inline_start + - pbm.margin.inline_start.auto_is(Length::zero).into(); + pbm.margin.inline_start.auto_is(Au::zero); let max_inline_end = (float_context.containing_block_info.inline_end - - pbm.margin.inline_end.auto_is(Length::zero).into()) + pbm.margin.inline_end.auto_is(Au::zero)) .max(min_inline_start + object_size.inline); PlacementAmongFloats { float_context, @@ -259,7 +259,7 @@ impl<'a> PlacementAmongFloats<'a> { pub(crate) fn set_inline_size(&mut self, inline_size: Au, pbm: &PaddingBorderMargin) { self.object_size.inline = inline_size; self.max_inline_end = (self.float_context.containing_block_info.inline_end - - pbm.margin.inline_end.auto_is(Length::zero).into()) + pbm.margin.inline_end.auto_is(Au::zero)) .max(self.min_inline_start + inline_size); } @@ -911,8 +911,8 @@ impl FloatBox { // Margin is computed this way regardless of whether the element is replaced // or non-replaced. let pbm = style.padding_border_margin(containing_block); - let margin = pbm.margin.auto_is(Length::zero); - let pbm_sums = &(&pbm.padding + &pbm.border) + &margin.clone().into(); + let margin = pbm.margin.auto_is(Au::zero); + let pbm_sums = &(&pbm.padding + &pbm.border) + &margin.clone(); let (content_size, children); match self.contents { @@ -951,7 +951,7 @@ impl FloatBox { layout_context, positioning_context, &containing_block_for_children, - &containing_block, + containing_block, ); content_size = LogicalVec2 { inline: inline_size, @@ -991,7 +991,7 @@ impl FloatBox { content_rect, pbm.padding.into(), pbm.border.into(), - margin, + margin.into(), // Clearance is handled internally by the float placement logic, so there's no need // to store it explicitly in the fragment. None, // clearance diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index ff8f6c8a02d..47f6f87558e 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -76,12 +76,13 @@ use gfx::font::FontMetrics; use gfx::text::glyph::GlyphStore; use serde::Serialize; use servo_arc::Arc; +use style::computed_values::vertical_align::T as VerticalAlign; use style::computed_values::white_space::T as WhiteSpace; use style::context::QuirksMode; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; -use style::values::computed::{Length, LengthPercentage}; -use style::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword}; +use style::values::computed::Length; +use style::values::generics::box_::VerticalAlignKeyword; use style::values::generics::text::LineHeight; use style::values::specified::text::{TextAlignKeyword, TextDecorationLine}; use style::values::specified::{TextAlignLast, TextJustify}; @@ -173,7 +174,7 @@ struct LineUnderConstruction { /// offset from `text-indent`. start_position: LogicalVec2, - /// The current inline position in the line being laid out into [`LineItems`] in this + /// The current inline position in the line being laid out into [`LineItem`]s in this /// [`InlineFormattingContext`] independent of the depth in the nesting level. inline_position: Length, @@ -187,7 +188,7 @@ struct LineUnderConstruction { has_content: bool, /// Whether or not there are floats that did not fit on the current line. Before - /// the [`LineItems`] of this line are laid out, these floats will need to be + /// the [`LineItem`]s of this line are laid out, these floats will need to be /// placed directly below this line, but still as children of this line's Fragments. has_floats_waiting_to_be_placed: bool, @@ -604,7 +605,7 @@ pub(super) struct InlineFormattingContextState<'a, 'b> { /// of the inline box is the state popped from the stack. inline_box_state_stack: Vec, - /// A vector of fragment that are laid out. This includes one [`Fragment::Anonymous`] + /// A vector of fragment that are laid out. This includes one [`Fragment::Positioning`] /// per line that is currently laid out plus fragments for all floats, which /// are currently laid out at the top-level of each [`InlineFormattingContext`]. fragments: Vec, @@ -724,7 +725,8 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { .pbm .margin .inline_start - .auto_is(Length::zero) + .auto_is(Au::zero) + .into() } let line_item = inline_box_state @@ -758,7 +760,12 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { if inline_box_state.is_last_fragment { let pbm_end = Length::from( inline_box_state.pbm.padding.inline_end + inline_box_state.pbm.border.inline_end, - ) + inline_box_state.pbm.margin.inline_end.auto_is(Length::zero); + ) + inline_box_state + .pbm + .margin + .inline_end + .auto_is(Au::zero) + .into(); self.current_line_segment.inline_size += pbm_end; } } @@ -964,7 +971,9 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { match text_align { TextAlign::Start => text_indent, TextAlign::End => (available_space - line_length).max(text_indent), - TextAlign::Center => (available_space - line_length + text_indent) / 2., + TextAlign::Center => { + ((available_space - line_length + text_indent) / 2.).max(text_indent) + }, }; // Calculate the justification adjustment. This is simply the remaining space on the line, @@ -1253,7 +1262,12 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { let strut_size = if using_fallback_font { // TODO(mrobinson): This value should probably be cached somewhere. let container_state = self.current_inline_container_state(); - let mut block_size = container_state.get_block_size_contribution(&font_metrics); + let vertical_align = effective_vertical_align( + &container_state.style, + self.inline_box_state_stack.last().map(|c| &c.base), + ); + let mut block_size = + container_state.get_block_size_contribution(vertical_align, &font_metrics); block_size.adjust_for_baseline_offset(container_state.baseline_offset); block_size } else if quirks_mode && !is_collapsible_whitespace { @@ -1384,14 +1398,11 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { // Place all floats in this unbreakable segment. let mut segment_items = mem::take(&mut self.current_line_segment.line_items); for item in segment_items.iter_mut() { - match item { - LineItem::Float(float_item) => { - self.place_float_line_item_for_commit_to_line( - float_item, - line_inline_size_without_trailing_whitespace, - ); - }, - _ => {}, + if let LineItem::Float(float_item) = item { + self.place_float_line_item_for_commit_to_line( + float_item, + line_inline_size_without_trailing_whitespace, + ); } } @@ -1450,7 +1461,7 @@ impl InlineFormattingContext { } } - fn foreach<'a>(&self, mut func: impl FnMut(InlineFormattingContextIterItem)) { + fn foreach(&self, mut func: impl FnMut(InlineFormattingContextIterItem)) { // TODO(mrobinson): Using OwnedRef here we could maybe avoid the second borrow when // iterating through members of each inline box. struct InlineFormattingContextChildBoxIter { @@ -1722,13 +1733,17 @@ impl InlineContainerState { let line_height = line_height(&style, &font_metrics); let mut baseline_offset = Au::zero(); - let mut strut_block_sizes = - Self::get_block_sizes_with_style(&style, &font_metrics, line_height); + let mut strut_block_sizes = Self::get_block_sizes_with_style( + effective_vertical_align(&style, parent_container), + &style, + &font_metrics, + line_height, + ); if let Some(parent_container) = parent_container { // The baseline offset from `vertical-align` might adjust where our block size contribution is // within the line. baseline_offset = parent_container.get_cumulative_baseline_offset_for_child( - style.effective_vertical_align_for_inline_layout(), + style.clone_vertical_align(), &strut_block_sizes, ); strut_block_sizes.adjust_for_baseline_offset(baseline_offset); @@ -1753,11 +1768,11 @@ impl InlineContainerState { } fn get_block_sizes_with_style( + vertical_align: VerticalAlign, style: &ComputedValues, font_metrics: &FontMetrics, line_height: Length, ) -> LineBlockSizes { - let vertical_align = style.effective_vertical_align_for_inline_layout(); if !is_baseline_relative(vertical_align) { return LineBlockSizes { line_height, @@ -1817,8 +1832,13 @@ impl InlineContainerState { } } - fn get_block_size_contribution(&self, font_metrics: &FontMetrics) -> LineBlockSizes { + fn get_block_size_contribution( + &self, + vertical_align: VerticalAlign, + font_metrics: &FontMetrics, + ) -> LineBlockSizes { Self::get_block_sizes_with_style( + vertical_align, &self.style, font_metrics, line_height(&self.style, font_metrics), @@ -1827,35 +1847,36 @@ impl InlineContainerState { fn get_cumulative_baseline_offset_for_child( &self, - child_vertical_align: GenericVerticalAlign, + child_vertical_align: VerticalAlign, child_block_size: &LineBlockSizes, ) -> Au { - let block_size = self.get_block_size_contribution(&self.font_metrics); + let block_size = + self.get_block_size_contribution(child_vertical_align.clone(), &self.font_metrics); self.baseline_offset + match child_vertical_align { // `top` and `bottom are not actually relative to the baseline, but this value is unused // in those cases. // TODO: We should distinguish these from `baseline` in order to implement "aligned subtrees" properly. // See https://drafts.csswg.org/css2/#aligned-subtree. - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Baseline) | - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Top) | - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => Au::zero(), - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Sub) => Au::from_f32_px( + VerticalAlign::Keyword(VerticalAlignKeyword::Baseline) | + VerticalAlign::Keyword(VerticalAlignKeyword::Top) | + VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => Au::zero(), + VerticalAlign::Keyword(VerticalAlignKeyword::Sub) => Au::from_f32_px( block_size .resolve() .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO) .px(), ), - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Super) => -Au::from_f32_px( + VerticalAlign::Keyword(VerticalAlignKeyword::Super) => -Au::from_f32_px( block_size .resolve() .scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO) .px(), ), - GenericVerticalAlign::Keyword(VerticalAlignKeyword::TextTop) => { + VerticalAlign::Keyword(VerticalAlignKeyword::TextTop) => { child_block_size.size_for_baseline_positioning.ascent - self.font_metrics.ascent }, - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Middle) => { + VerticalAlign::Keyword(VerticalAlignKeyword::Middle) => { // "Align the vertical midpoint of the box with the baseline of the parent // box plus half the x-height of the parent." (child_block_size.size_for_baseline_positioning.ascent - @@ -1863,11 +1884,11 @@ impl InlineContainerState { self.font_metrics.x_height) .scale_by(0.5) }, - GenericVerticalAlign::Keyword(VerticalAlignKeyword::TextBottom) => { + VerticalAlign::Keyword(VerticalAlignKeyword::TextBottom) => { self.font_metrics.descent - child_block_size.size_for_baseline_positioning.descent }, - GenericVerticalAlign::Length(length_percentage) => { + VerticalAlign::Length(length_percentage) => { Au::from_f32_px(-length_percentage.resolve(child_block_size.line_height).px()) }, } @@ -1925,8 +1946,8 @@ impl IndependentFormattingContext { ) { let style = self.style(); let pbm = style.padding_border_margin(ifc.containing_block); - let margin = pbm.margin.auto_is(Length::zero); - let pbm_sums = &(&pbm.padding + &pbm.border) + &margin.clone().into(); + let margin = pbm.margin.auto_is(Au::zero); + let pbm_sums = &(&pbm.padding + &pbm.border) + &margin.clone(); let mut child_positioning_context = None; // We need to know the inline size of the atomic before deciding whether to do the line break. @@ -1953,7 +1974,7 @@ impl IndependentFormattingContext { content_rect.into(), pbm.padding.into(), pbm.border.into(), - margin, + margin.into(), None, /* clearance */ CollapsedBlockMargins::zero(), ) @@ -2006,7 +2027,7 @@ impl IndependentFormattingContext { layout_context, child_positioning_context.as_mut().unwrap(), &containing_block_for_children, - &ifc.containing_block, + ifc.containing_block, ); let (inline_size, block_size) = match independent_layout.content_inline_size_for_table { @@ -2042,7 +2063,7 @@ impl IndependentFormattingContext { content_rect.into(), pbm.padding.into(), pbm.border.into(), - margin, + margin.into(), None, CollapsedBlockMargins::zero(), ) @@ -2134,15 +2155,12 @@ impl FloatBox { } } -fn place_pending_floats(ifc: &mut InlineFormattingContextState, line_items: &mut Vec) { +fn place_pending_floats(ifc: &mut InlineFormattingContextState, line_items: &mut [LineItem]) { for item in line_items.iter_mut() { - match item { - LineItem::Float(float_line_item) => { - if float_line_item.needs_placement { - ifc.place_float_fragment(&mut float_line_item.fragment); - } - }, - _ => {}, + if let LineItem::Float(float_line_item) = item { + if float_line_item.needs_placement { + ifc.place_float_fragment(&mut float_line_item.fragment); + } } } } @@ -2156,14 +2174,28 @@ fn line_height(parent_style: &ComputedValues, font_metrics: &FontMetrics) -> Len } } -fn is_baseline_relative(vertical_align: GenericVerticalAlign) -> bool { - match vertical_align { - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Top) | - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => false, - _ => true, +fn effective_vertical_align( + style: &ComputedValues, + container: Option<&InlineContainerState>, +) -> VerticalAlign { + if container.is_none() { + // If we are at the root of the inline formatting context, we shouldn't use the + // computed `vertical-align`, since it has no effect on the contents of this IFC + // (it can just affect how the block container is aligned within the parent IFC). + VerticalAlign::Keyword(VerticalAlignKeyword::Baseline) + } else { + style.clone_vertical_align() } } +fn is_baseline_relative(vertical_align: VerticalAlign) -> bool { + !matches!( + vertical_align, + VerticalAlign::Keyword(VerticalAlignKeyword::Top) | + VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) + ) +} + /// Whether or not a strut should be created for an inline container. Normally /// all inline containers get struts. In quirks mode this isn't always the case /// though. @@ -2215,9 +2247,9 @@ struct ContentSizesComputation<'a> { paragraph: ContentSizes, current_line: ContentSizes, /// Size for whitepsace pending to be added to this line. - pending_whitespace: Length, - /// Whether or not this IFC has seen any non-whitespace content. - had_non_whitespace_content_yet: bool, + pending_whitespace: Au, + /// Whether or not this IFC has seen any content, excluding collapsed whitespace. + had_content_yet: bool, /// Stack of ending padding, margin, and border to add to the length /// when an inline box finishes. ending_inline_pbm_stack: Vec, @@ -2270,34 +2302,37 @@ impl<'a> ContentSizesComputation<'a> { } for run in segment.runs.iter() { - let advance = Length::from(run.glyph_store.total_advance()); + let advance = run.glyph_store.total_advance(); - if !run.glyph_store.is_whitespace() { - self.had_non_whitespace_content_yet = true; - self.current_line.min_content += advance.into(); - self.current_line.max_content += - (self.pending_whitespace + advance).into(); - self.pending_whitespace = Length::zero(); - } else { + if run.glyph_store.is_whitespace() { // If this run is a forced line break, we *must* break the line // and start measuring from the inline origin once more. - if text_run.glyph_run_is_whitespace_ending_with_preserved_newline(run) { - self.had_non_whitespace_content_yet = true; + if text_run.glyph_run_is_preserved_newline(run) { + self.had_content_yet = true; self.forced_line_break(); self.current_line = ContentSizes::zero(); continue; } - // Discard any leading whitespace in the IFC. This will always be trimmed. - if !self.had_non_whitespace_content_yet { + let white_space = + text_run.parent_style.get_inherited_text().white_space; + // TODO: need to handle white_space.allow_wrap() too. + if !white_space.preserve_spaces() { + // Discard any leading whitespace in the IFC. This will always be trimmed. + if self.had_content_yet { + // Wait to take into account other whitespace until we see more content. + // Whitespace at the end of the IFC will always be trimmed. + self.line_break_opportunity(); + self.pending_whitespace += advance; + } continue; } - - // Wait to take into account other whitespace until we see more content. - // Whitespace at the end of the IFC will always be trimmed. - self.line_break_opportunity(); - self.pending_whitespace += advance; } + + self.had_content_yet = true; + self.current_line.min_content += advance; + self.current_line.max_content += self.pending_whitespace + advance; + self.pending_whitespace = Au::zero(); } } }, @@ -2307,11 +2342,10 @@ impl<'a> ContentSizesComputation<'a> { self.containing_block_writing_mode, ); - self.current_line.min_content += - (self.pending_whitespace + outer.min_content.into()).into(); - self.current_line.max_content += outer.max_content; - self.pending_whitespace = Length::zero(); - self.had_non_whitespace_content_yet = true; + self.current_line.min_content += self.pending_whitespace + outer.min_content; + self.current_line.max_content += self.pending_whitespace + outer.max_content; + self.pending_whitespace = Au::zero(); + self.had_content_yet = true; }, _ => {}, }); @@ -2349,8 +2383,8 @@ impl<'a> ContentSizesComputation<'a> { containing_block_writing_mode, paragraph: ContentSizes::zero(), current_line: ContentSizes::zero(), - pending_whitespace: Length::zero(), - had_non_whitespace_content_yet: false, + pending_whitespace: Au::zero(), + had_content_yet: false, ending_inline_pbm_stack: Vec::new(), } .traverse(inline_formatting_context) diff --git a/components/layout_2020/flow/line.rs b/components/layout_2020/flow/line.rs index dce1d304fa9..9661fe0d819 100644 --- a/components/layout_2020/flow/line.rs +++ b/components/layout_2020/flow/line.rs @@ -10,7 +10,7 @@ use gfx::font::FontMetrics; use gfx::text::glyph::GlyphStore; use servo_arc::Arc; use style::properties::ComputedValues; -use style::values::computed::{Length, LengthPercentage}; +use style::values::computed::Length; use style::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword}; use style::values::generics::text::LineHeight; use style::values::specified::box_::DisplayOutside; @@ -28,7 +28,7 @@ use crate::geom::{LogicalRect, LogicalVec2}; use crate::positioned::{ relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, }; -use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::PaddingBorderMargin; use crate::ContainingBlock; pub(super) struct LineMetrics { @@ -38,7 +38,7 @@ pub(super) struct LineMetrics { /// The block size of this line. pub block_size: Length, - /// The block offset of this line's baseline from [`Self:block_offset`]. + /// The block offset of this line's baseline from [`Self::block_offset`]. pub baseline_block_offset: Au, } @@ -51,7 +51,7 @@ pub(super) struct LineItemLayoutState<'a> { pub parent_offset: LogicalVec2, /// The block offset of the parent's baseline relative to the block start of the line. This - /// is often the same as [`Self::block_offset_of_parent`], but can be different for the root + /// is often the same as [`Self::parent_offset`], but can be different for the root /// element. pub baseline_offset: Au, @@ -226,16 +226,10 @@ impl TextRunLineItem { // The block start of the TextRun is often zero (meaning it has the same font metrics as the // inline box's strut), but for children of the inline formatting context root or for // fallback fonts that use baseline relatve alignment, it might be different. - let mut start_corner = &LogicalVec2 { + let start_corner = &LogicalVec2 { inline: state.inline_position, block: (state.baseline_offset - self.font_metrics.ascent).into(), } - &state.parent_offset; - if !is_baseline_relative( - self.parent_style - .effective_vertical_align_for_inline_layout(), - ) { - start_corner.block = Length::zero(); - } let rect = LogicalRect { start_corner, @@ -294,19 +288,19 @@ impl InlineBoxLineItem { let style = self.style.clone(); let mut padding = self.pbm.padding.clone(); let mut border = self.pbm.border.clone(); - let mut margin = self.pbm.margin.auto_is(Length::zero); + let mut margin = self.pbm.margin.auto_is(Au::zero); if !self.is_first_fragment { padding.inline_start = Au::zero(); border.inline_start = Au::zero(); - margin.inline_start = Length::zero(); + margin.inline_start = Au::zero(); } if !self.is_last_fragment_of_ib_split { padding.inline_end = Au::zero(); border.inline_end = Au::zero(); - margin.inline_end = Length::zero(); + margin.inline_end = Au::zero(); } - let pbm_sums = &(&padding + &border) + &margin.map(|t| (*t).into()); + let pbm_sums = &(&padding + &border) + &margin; state.inline_position += pbm_sums.inline_start.into(); let space_above_baseline = self.calculate_space_above_baseline(); @@ -342,9 +336,9 @@ impl InlineBoxLineItem { if !self.is_last_fragment_of_ib_split || !saw_end { padding.inline_end = Au::zero(); border.inline_end = Au::zero(); - margin.inline_end = Length::zero(); + margin.inline_end = Au::zero(); } - let pbm_sums = &(&padding + &border) + &margin.clone().into(); + let pbm_sums = &(&padding + &border) + &margin.clone(); // If the inline box didn't have any content at all, don't add a Fragment for it. let box_has_padding_border_or_margin = pbm_sums.inline_sum() > Au::zero(); @@ -385,7 +379,7 @@ impl InlineBoxLineItem { content_rect, padding.into(), border.into(), - margin, + margin.into(), None, /* clearance */ CollapsedBlockMargins::zero(), ); @@ -428,12 +422,11 @@ impl InlineBoxLineItem { /// Given the state for a line item layout and the space above the baseline for this inline /// box, find the block start position relative to the line block start position. fn calculate_block_start(&self, state: &LineItemLayoutState, space_above_baseline: Au) -> Au { - let vertical_align = self.style.effective_vertical_align_for_inline_layout(); let line_gap = self.font_metrics.line_gap; // The baseline offset that we have in `Self::baseline_offset` is relative to the line // baseline, so we need to make it relative to the line block start. - match vertical_align { + match self.style.clone_vertical_align() { GenericVerticalAlign::Keyword(VerticalAlignKeyword::Top) => { let line_height: Au = line_height(&self.style, &self.font_metrics).into(); (line_height - line_gap).scale_by(0.5) @@ -586,14 +579,6 @@ impl FloatLineItem { } } -fn is_baseline_relative(vertical_align: GenericVerticalAlign) -> bool { - match vertical_align { - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Top) | - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => false, - _ => true, - } -} - fn line_height(parent_style: &ComputedValues, font_metrics: &FontMetrics) -> Length { let font_size = parent_style.get_font().font_size.computed_size(); match parent_style.get_inherited_text().line_height { diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 4f8afbe741b..8a0b1735006 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -64,7 +64,7 @@ impl BlockContainer { BlockContainer::BlockLevelBoxes(boxes) => boxes .iter() .any(|block_level_box| block_level_box.borrow().contains_floats()), - BlockContainer::InlineFormattingContext { .. } => true, + BlockContainer::InlineFormattingContext(context) => context.contains_floats, } } } @@ -116,8 +116,8 @@ impl BlockLevelBox { } let pbm = style.padding_border_margin(containing_block); - let start_margin = pbm.margin.block_start.auto_is(Length::zero); - collected_margin.adjoin_assign(&CollapsedMargin::new(start_margin)); + let start_margin = pbm.margin.block_start.auto_is(Au::zero); + collected_margin.adjoin_assign(&CollapsedMargin::new(start_margin.into())); let child_boxes = match self { BlockLevelBox::SameFormattingContextBlock { ref contents, .. } => match contents { @@ -140,11 +140,13 @@ impl BlockLevelBox { .content_box_size(containing_block, &pbm) .inline .auto_is(|| { - let margin_inline_start = pbm.margin.inline_start.auto_is(Length::zero); - let margin_inline_end = pbm.margin.inline_end.auto_is(Length::zero); - Length::from(containing_block.inline_size - pbm.padding_border_sums.inline) - + let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero); + let margin_inline_end = pbm.margin.inline_end.auto_is(Au::zero); + (containing_block.inline_size - + pbm.padding_border_sums.inline - margin_inline_start - - margin_inline_end + margin_inline_end) + .into() }) .clamp_between_extremums(min_inline_size, max_inline_size); @@ -173,8 +175,8 @@ impl BlockLevelBox { return false; } - let end_margin = pbm.margin.block_end.auto_is(Length::zero); - collected_margin.adjoin_assign(&CollapsedMargin::new(end_margin)); + let end_margin = pbm.margin.block_end.auto_is(Au::zero); + collected_margin.adjoin_assign(&CollapsedMargin::new(end_margin.into())); true } @@ -613,6 +615,7 @@ impl BlockLevelBox { /// /// - /// - +#[allow(clippy::too_many_arguments)] fn layout_in_flow_non_replaced_block_level_same_formatting_context( layout_context: &LayoutContext, positioning_context: &mut PositioningContext, @@ -856,7 +859,7 @@ impl NonReplacedFormattingContext { layout_context, positioning_context, &containing_block_for_children, - &containing_block, + containing_block, ); let (block_size, inline_size) = match layout.content_inline_size_for_table { @@ -932,7 +935,7 @@ impl NonReplacedFormattingContext { let effective_margin_inline_start; let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(&pbm); - let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); + let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start.into()); // From https://drafts.csswg.org/css2/#floats: // "The border box of a table, a block-level replaced element, or an element in @@ -1110,10 +1113,10 @@ impl NonReplacedFormattingContext { } let margin = LogicalSides { - inline_start: margin_inline_start, - inline_end: margin_inline_end, - block_start: margin_block_start, - block_end: margin_block_end, + inline_start: margin_inline_start.into(), + inline_end: margin_inline_end.into(), + block_start: margin_block_start.into(), + block_end: margin_block_end.into(), }; // Clearance prevents margin collapse between this block and previous ones, @@ -1138,7 +1141,7 @@ impl NonReplacedFormattingContext { clearance.unwrap_or_else(Length::zero).into(), inline: pbm.padding.inline_start + pbm.border.inline_start + - effective_margin_inline_start.into(), + effective_margin_inline_start, }, size: content_size.into(), }; @@ -1162,7 +1165,7 @@ impl NonReplacedFormattingContext { /// /// /// -fn layout_in_flow_replaced_block_level<'a>( +fn layout_in_flow_replaced_block_level( containing_block: &ContainingBlock, base_fragment_info: BaseFragmentInfo, style: &Arc, @@ -1190,7 +1193,7 @@ fn layout_in_flow_replaced_block_level<'a>( // sufficient space. They may even make the border box of said element narrower // than defined by section 10.3.3. CSS 2 does not define when a UA may put said // element next to the float or by how much said element may become narrower." - let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); + let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start.into()); let size = &content_size + &pbm.padding_border_sums.clone(); ( clearance, @@ -1216,7 +1219,7 @@ fn layout_in_flow_replaced_block_level<'a>( sequential_layout_state.collapse_margins(); sequential_layout_state .advance_block_position(size.block + clearance.unwrap_or_else(Length::zero).into()); - sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end)); + sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end.into())); } else { clearance = None; ( @@ -1230,19 +1233,17 @@ fn layout_in_flow_replaced_block_level<'a>( }; let margin = LogicalSides { - inline_start: margin_inline_start, - inline_end: margin_inline_end, - block_start: margin_block_start, - block_end: margin_block_end, + inline_start: margin_inline_start.into(), + inline_end: margin_inline_end.into(), + block_start: margin_block_start.into(), + block_end: margin_block_end.into(), }; let start_corner = LogicalVec2 { block: pbm.padding.block_start + pbm.border.block_start + clearance.unwrap_or_else(Length::zero).into(), - inline: pbm.padding.inline_start + - pbm.border.inline_start + - effective_margin_inline_start.into(), + inline: pbm.padding.inline_start + pbm.border.inline_start + effective_margin_inline_start, }; let content_rect = LogicalRect { @@ -1305,11 +1306,13 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( let inline_size = box_size .inline .auto_is(|| { - let margin_inline_start = pbm.margin.inline_start.auto_is(Length::zero); - let margin_inline_end = pbm.margin.inline_end.auto_is(Length::zero); - Length::from(containing_block.inline_size - pbm.padding_border_sums.inline) - + let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero); + let margin_inline_end = pbm.margin.inline_end.auto_is(Au::zero); + (containing_block.inline_size - + pbm.padding_border_sums.inline - margin_inline_start - - margin_inline_end + margin_inline_end) + .into() }) .clamp_between_extremums(min_box_size.inline, max_box_size.inline); @@ -1348,46 +1351,46 @@ fn solve_margins( inline_size: Length, ) -> ResolvedMargins { let (inline_margins, effective_margin_inline_start) = - solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, inline_size); - let block_margins = solve_block_margins_for_in_flow_block_level(&pbm); + solve_inline_margins_for_in_flow_block_level(containing_block, pbm, inline_size); + let block_margins = solve_block_margins_for_in_flow_block_level(pbm); ResolvedMargins { margin: LogicalSides { - inline_start: inline_margins.0, - inline_end: inline_margins.1, - block_start: block_margins.0, - block_end: block_margins.1, + inline_start: inline_margins.0.into(), + inline_end: inline_margins.1.into(), + block_start: block_margins.0.into(), + block_end: block_margins.1.into(), }, - effective_margin_inline_start, + effective_margin_inline_start: effective_margin_inline_start.into(), } } /// Resolves 'auto' margins of an in-flow block-level box in the block axis. /// /// -fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Length, Length) { +fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Au, Au) { ( - pbm.margin.block_start.auto_is(Length::zero), - pbm.margin.block_end.auto_is(Length::zero), + pbm.margin.block_start.auto_is(Au::zero), + pbm.margin.block_end.auto_is(Au::zero), ) } /// This is supposed to handle 'justify-self', but no browser supports it on block boxes. -/// Instead,
and
are implemented via internal 'text-align' values. +/// Instead, `
` and `
` are implemented via internal 'text-align' values. /// The provided free space should already take margins into account. In particular, /// it should be zero if there is an auto margin. /// -fn justify_self_alignment(containing_block: &ContainingBlock, free_space: Length) -> Length { +fn justify_self_alignment(containing_block: &ContainingBlock, free_space: Au) -> Au { let style = containing_block.style; - debug_assert!(free_space >= Length::zero()); + debug_assert!(free_space >= Au::zero()); match style.clone_text_align() { - TextAlignKeyword::ServoCenter => free_space / 2., + TextAlignKeyword::ServoCenter => free_space / 2, TextAlignKeyword::ServoLeft if !style.writing_mode.line_left_is_inline_start() => { free_space }, TextAlignKeyword::ServoRight if style.writing_mode.line_left_is_inline_start() => { free_space }, - _ => Length::zero(), + _ => Au::zero(), } } @@ -1407,25 +1410,25 @@ fn solve_inline_margins_for_in_flow_block_level( containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, inline_size: Length, -) -> ((Length, Length), Length) { +) -> ((Au, Au), Au) { let free_space = - Length::from(containing_block.inline_size - pbm.padding_border_sums.inline) - inline_size; - let mut justification = Length::zero(); + containing_block.inline_size - pbm.padding_border_sums.inline - inline_size.into(); + let mut justification = Au::zero(); let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) { - (LengthOrAuto::Auto, LengthOrAuto::Auto) => { - let start = Length::zero().max(free_space / 2.); + (AuOrAuto::Auto, AuOrAuto::Auto) => { + let start = Au::zero().max(free_space / 2); (start, free_space - start) }, - (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => { - (Length::zero().max(free_space - end), end) + (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => { + (Au::zero().max(free_space - end), end) }, - (LengthOrAuto::LengthPercentage(start), LengthOrAuto::Auto) => (start, free_space - start), - (LengthOrAuto::LengthPercentage(start), LengthOrAuto::LengthPercentage(end)) => { + (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start), + (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => { // In the cases above, the free space is zero after taking 'auto' margins into account. // But here we may still have some free space to perform 'justify-self' alignment. // This aligns the margin box within the containing block, or in other words, // aligns the border box within the margin-shrunken containing block. - let free_space = Length::zero().max(free_space - start - end); + let free_space = Au::zero().max(free_space - start - end); justification = justify_self_alignment(containing_block, free_space); (start, end) }, @@ -1449,25 +1452,21 @@ fn solve_inline_margins_avoiding_floats( pbm: &PaddingBorderMargin, inline_size: Length, placement_rect: LogicalRect, -) -> ((Length, Length), Length) { - let free_space = placement_rect.size.inline - inline_size; - debug_assert!(free_space >= Length::zero()); +) -> ((Au, Au), Au) { + let free_space = Au::from(placement_rect.size.inline - inline_size); + debug_assert!(free_space >= Au::zero()); let cb_info = &sequential_layout_state.floats.containing_block_info; - let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start.into(); - let end_adjustment = Length::from(cb_info.inline_end) - placement_rect.max_inline_position(); - let mut justification = Length::zero(); + let start_adjustment = Au::from(placement_rect.start_corner.inline) - cb_info.inline_start; + let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position().into(); + let mut justification = Au::zero(); let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) { - (LengthOrAuto::Auto, LengthOrAuto::Auto) => { - let half = free_space / 2.; + (AuOrAuto::Auto, AuOrAuto::Auto) => { + let half = free_space / 2; (start_adjustment + half, end_adjustment + free_space - half) }, - (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => { - (start_adjustment + free_space, end) - }, - (LengthOrAuto::LengthPercentage(start), LengthOrAuto::Auto) => { - (start, end_adjustment + free_space) - }, - (LengthOrAuto::LengthPercentage(start), LengthOrAuto::LengthPercentage(end)) => { + (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end), + (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space), + (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => { // The spec says 'justify-self' aligns the margin box within the float-shrunken // containing block. That's wrong (https://github.com/w3c/csswg-drafts/issues/9963), // and Blink and WebKit are broken anyways. So we match Gecko instead: this aligns @@ -1493,7 +1492,7 @@ fn solve_clearance_and_inline_margins_avoiding_floats( pbm: &PaddingBorderMargin, size: LogicalVec2, style: &Arc, -) -> (Option, (Length, Length), Length) { +) -> (Option, (Au, Au), Au) { let (clearance, placement_rect) = sequential_layout_state .calculate_clearance_and_inline_adjustment( style.get_box().clear, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index cd2ab4dfe8a..11d7ee5ba27 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -3,13 +3,16 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use atomic_refcell::AtomicRef; -use script_layout_interface::wrapper_traits::LayoutNode; +use script_layout_interface::wrapper_traits::{ + LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, +}; use script_layout_interface::{LayoutElementType, LayoutNodeType}; +use script_traits::compositor::ScrollSensitivity; use serde::Serialize; use servo_arc::Arc; use style::dom::OpaqueNode; use style::properties::ComputedValues; -use style::values::computed::Length; +use style::values::computed::{Length, Overflow}; use style_traits::CSSPixel; use crate::cell::ArcRefCell; @@ -36,6 +39,9 @@ pub struct BoxTree { /// canvas_background: CanvasBackground, + + /// Whether or not the root element should be sensitive to scrolling input events. + sensitive_to_scroll_input: bool, } impl BoxTree { @@ -48,6 +54,35 @@ impl BoxTree { // Zero box for `:root { display: none }`, one for the root element otherwise. assert!(boxes.len() <= 1); + // From https://drafts.csswg.org/css-overflow/#propdef-overflow: + // > UAs must apply the overflow-* values set on the root element to the viewport when the + // > root element’s display value is not none. However, when the root element is an [HTML] + // > html element (including XML syntax for HTML) whose overflow value is visible (in both + // > axes), and that element has as a child a body element whose display value is also not + // > none, user agents must instead apply the overflow-* values of the first such child + // > element to the viewport. The element from which the value is propagated must then have a + // > used overflow value of visible. + // + // TODO: This should handle when different overflow is set multiple axes, which requires the + // compositor scroll tree to allow setting a value per axis. + let root_style = root_element.style(context); + let mut root_overflow = root_style.get_box().overflow_y; + if root_overflow == Overflow::Visible && !root_style.get_box().display.is_none() { + for child in iter_child_nodes(root_element) { + if !child.to_threadsafe().as_element().map_or(false, |element| { + element.is_body_element_of_html_element_root() + }) { + continue; + } + + let style = child.style(context); + if !style.get_box().display.is_none() { + root_overflow = style.get_box().overflow_y; + break; + } + } + } + let contents = BlockContainer::BlockLevelBoxes(boxes); let contains_floats = contents.contains_floats(); Self { @@ -56,6 +91,7 @@ impl BoxTree { contains_floats, }, canvas_background: CanvasBackground::for_root_element(context, root_element), + sensitive_to_scroll_input: root_overflow != Overflow::Hidden, } } @@ -83,6 +119,7 @@ impl BoxTree { where Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync, { + #[allow(clippy::enum_variant_names)] enum UpdatePoint { AbsolutelyPositionedBlockLevelBox(ArcRefCell), AbsolutelyPositionedInlineLevelBox(ArcRefCell), @@ -251,6 +288,7 @@ fn construct_for_root_element<'dom>( propagated_text_decoration_line, )) }; + let root_box = ArcRefCell::new(root_box); root_element .element_box_slot() @@ -329,11 +367,18 @@ impl BoxTree { acc.union(&child_overflow) }); + let root_scroll_sensitivity = if self.sensitive_to_scroll_input { + ScrollSensitivity::ScriptAndInputEvents + } else { + ScrollSensitivity::Script + }; + FragmentTree { root_fragments, scrollable_overflow, initial_containing_block: physical_containing_block, canvas_background: self.canvas_background.clone(), + root_scroll_sensitivity, } } } diff --git a/components/layout_2020/flow/text_run.rs b/components/layout_2020/flow/text_run.rs index 117cf37b915..1f237d6a8a4 100644 --- a/components/layout_2020/flow/text_run.rs +++ b/components/layout_2020/flow/text_run.rs @@ -36,7 +36,7 @@ const XI_LINE_BREAKING_CLASS_ZW: u8 = 28; const XI_LINE_BREAKING_CLASS_WJ: u8 = 30; const XI_LINE_BREAKING_CLASS_ZWJ: u8 = 40; -/// https://www.w3.org/TR/css-display-3/#css-text-run +/// #[derive(Debug, Serialize)] pub(crate) struct TextRun { pub base_fragment_info: BaseFragmentInfo, @@ -76,7 +76,7 @@ enum SegmentStartSoftWrapPolicy { #[derive(Debug, Serialize)] pub(crate) struct TextRunSegment { - /// The index of this font in the parent [`InlineFormattingContext`]'s collection of font + /// The index of this font in the parent [`super::InlineFormattingContext`]'s collection of font /// information. pub font_index: usize, @@ -150,7 +150,7 @@ impl TextRunSegment { // If this whitespace forces a line break, queue up a hard line break the next time we // see any content. We don't line break immediately, because we'd like to finish processing // any ongoing inline boxes before ending the line. - if text_run.glyph_run_is_whitespace_ending_with_preserved_newline(run) { + if text_run.glyph_run_is_preserved_newline(run) { ifc.defer_forced_line_break(); continue; } @@ -426,11 +426,8 @@ impl TextRun { self.prevent_soft_wrap_opportunity_at_end; } - pub(super) fn glyph_run_is_whitespace_ending_with_preserved_newline( - &self, - run: &GlyphRun, - ) -> bool { - if !run.glyph_store.is_whitespace() { + pub(super) fn glyph_run_is_preserved_newline(&self, run: &GlyphRun) -> bool { + if !run.glyph_store.is_whitespace() || run.range.length() != ByteIndex(1) { return false; } if !self @@ -442,15 +439,15 @@ impl TextRun { return false; } - let last_byte = self.text.as_bytes().get(run.range.end().to_usize() - 1); - last_byte == Some(&b'\n') + let byte = self.text.as_bytes().get(run.range.begin().to_usize()); + byte == Some(&b'\n') } } /// Whether or not this character will rpevent a soft wrap opportunity when it /// comes before or after an atomic inline element. /// -/// From https://www.w3.org/TR/css-text-3/#line-break-details: +/// From : /// /// > For Web-compatibility there is a soft wrap opportunity before and after each /// > replaced element or other atomic inline, even when adjacent to a character that @@ -524,7 +521,7 @@ pub struct WhitespaceCollapse { white_space: WhiteSpace, /// Whether or not we should collapse white space completely at the start of the string. - /// This is true when the last character handled in our owning [`InlineFormattingContext`] + /// This is true when the last character handled in our owning [`super::InlineFormattingContext`] /// was collapsible white space. remove_collapsible_white_space_at_start: bool, @@ -709,7 +706,7 @@ pub struct TextTransformation { pending_case_conversion_result: Option, } -impl<'a, InputIterator> TextTransformation { +impl TextTransformation { pub fn new(char_iterator: InputIterator, text_transform: TextTransform) -> Self { Self { char_iterator, diff --git a/components/layout_2020/fragment_tree/base_fragment.rs b/components/layout_2020/fragment_tree/base_fragment.rs index a43e375f26c..ac29bcc976d 100644 --- a/components/layout_2020/fragment_tree/base_fragment.rs +++ b/components/layout_2020/fragment_tree/base_fragment.rs @@ -47,8 +47,8 @@ impl BaseFragment { /// Information necessary to construct a new BaseFragment. #[derive(Clone, Copy, Debug, Serialize)] pub(crate) struct BaseFragmentInfo { - /// The tag to use for the new BaseFragment. - pub tag: Tag, + /// The tag to use for the new BaseFragment, if it is not an anonymous Fragment. + pub tag: Option, /// The flags to use for the new BaseFragment. pub flags: FragmentFlags, @@ -57,7 +57,14 @@ pub(crate) struct BaseFragmentInfo { impl BaseFragmentInfo { pub(crate) fn new_for_node(node: OpaqueNode) -> Self { Self { - tag: Tag::new(node), + tag: Some(Tag::new(node)), + flags: FragmentFlags::empty(), + } + } + + pub(crate) fn anonymous() -> Self { + Self { + tag: None, flags: FragmentFlags::empty(), } } @@ -66,7 +73,7 @@ impl BaseFragmentInfo { impl From for BaseFragment { fn from(info: BaseFragmentInfo) -> Self { Self { - tag: Some(info.tag), + tag: info.tag, debug_id: DebugId::new(), flags: info.flags, } @@ -110,7 +117,7 @@ impl Tag { self.pseudo.is_some() } - pub(crate) fn to_display_list_fragment_id(&self) -> u64 { + pub(crate) fn to_display_list_fragment_id(self) -> u64 { let fragment_type = match self.pseudo { Some(PseudoElement::Before) => FragmentType::BeforePseudoContent, Some(PseudoElement::After) => FragmentType::AfterPseudoContent, diff --git a/components/layout_2020/fragment_tree/box_fragment.rs b/components/layout_2020/fragment_tree/box_fragment.rs index 031285360a7..ad1b743242b 100644 --- a/components/layout_2020/fragment_tree/box_fragment.rs +++ b/components/layout_2020/fragment_tree/box_fragment.rs @@ -21,6 +21,19 @@ use crate::geom::{ }; use crate::style_ext::ComputedValuesExt; +/// Describes how a [`BoxFragment`] paints its background. +pub(crate) enum BackgroundMode { + /// Draw the normal [`BoxFragment`] background as well as the extra backgrounds + /// based on the style and positioning rectangles in this data structure. + Extra(Vec), + /// Do not draw a background for this Fragment. This is used for elements like + /// table tracks and table track groups, which rely on cells to paint their + /// backgrounds. + None, + /// Draw the background normally, getting information from the Fragment style. + Normal, +} + pub(crate) struct ExtraBackground { pub style: ServoArc, pub rect: LogicalRect, @@ -70,10 +83,11 @@ pub(crate) struct BoxFragment { pub(crate) resolved_sticky_insets: Option>, #[serde(skip_serializing)] - pub extra_backgrounds: Vec, + pub background_mode: BackgroundMode, } impl BoxFragment { + #[allow(clippy::too_many_arguments)] pub fn new( base_fragment_info: BaseFragmentInfo, style: ServoArc, @@ -108,6 +122,7 @@ impl BoxFragment { ) } + #[allow(clippy::too_many_arguments)] pub fn new_with_overconstrained( base_fragment_info: BaseFragmentInfo, style: ServoArc, @@ -158,7 +173,7 @@ impl BoxFragment { scrollable_overflow_from_children, overconstrained, resolved_sticky_insets: None, - extra_backgrounds: Vec::new(), + background_mode: BackgroundMode::Normal, } } @@ -176,7 +191,14 @@ impl BoxFragment { } pub fn add_extra_background(&mut self, extra_background: ExtraBackground) { - self.extra_backgrounds.push(extra_background); + match self.background_mode { + BackgroundMode::Extra(ref mut backgrounds) => backgrounds.push(extra_background), + _ => self.background_mode = BackgroundMode::Extra(vec![extra_background]), + } + } + + pub fn set_does_not_paint_background(&mut self) { + self.background_mode = BackgroundMode::None; } pub fn scrollable_overflow( diff --git a/components/layout_2020/fragment_tree/fragment_tree.rs b/components/layout_2020/fragment_tree/fragment_tree.rs index 4bce1e9b125..2957d3e2c36 100644 --- a/components/layout_2020/fragment_tree/fragment_tree.rs +++ b/components/layout_2020/fragment_tree/fragment_tree.rs @@ -6,6 +6,7 @@ use app_units::Au; use euclid::default::{Point2D, Rect, Size2D}; use fxhash::FxHashSet; use gfx_traits::print_tree::PrintTree; +use script_traits::compositor::ScrollSensitivity; use serde::Serialize; use style::animation::AnimationSetKey; use style::dom::OpaqueNode; @@ -40,6 +41,9 @@ pub struct FragmentTree { /// #[serde(skip)] pub(crate) canvas_background: CanvasBackground, + + /// Whether or not the root element is sensitive to scroll input events. + pub root_scroll_sensitivity: ScrollSensitivity, } impl FragmentTree { diff --git a/components/layout_2020/fragment_tree/hoisted_shared_fragment.rs b/components/layout_2020/fragment_tree/hoisted_shared_fragment.rs index 62822d4d610..ee6ce9870d6 100644 --- a/components/layout_2020/fragment_tree/hoisted_shared_fragment.rs +++ b/components/layout_2020/fragment_tree/hoisted_shared_fragment.rs @@ -56,16 +56,12 @@ pub(crate) enum AbsoluteBoxOffsets { impl AbsoluteBoxOffsets { pub(crate) fn both_specified(&self) -> bool { - match self { - AbsoluteBoxOffsets::Both { .. } => true, - _ => false, - } + matches!(self, AbsoluteBoxOffsets::Both { .. }) } pub(crate) fn adjust_offset(&mut self, new_offset: Length) { - match *self { - AbsoluteBoxOffsets::StaticStart { ref mut start } => *start = new_offset, - _ => (), + if let AbsoluteBoxOffsets::StaticStart { ref mut start } = *self { + *start = new_offset } } } diff --git a/components/layout_2020/fragment_tree/mod.rs b/components/layout_2020/fragment_tree/mod.rs index 4579638685a..8738f2a6af7 100644 --- a/components/layout_2020/fragment_tree/mod.rs +++ b/components/layout_2020/fragment_tree/mod.rs @@ -6,6 +6,7 @@ mod base_fragment; mod box_fragment; mod containing_block; mod fragment; +#[allow(clippy::module_inception)] mod fragment_tree; mod hoisted_shared_fragment; mod positioning_fragment; diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index bf7f9b44b98..6a57b3c997b 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -4,7 +4,7 @@ use std::convert::From; use std::fmt; -use std::ops::{Add, AddAssign, Sub}; +use std::ops::{Add, AddAssign, Sub, SubAssign}; use app_units::Au; use serde::Serialize; @@ -26,7 +26,7 @@ pub type LengthOrAuto = AutoOr; pub type AuOrAuto = AutoOr; pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>; -#[derive(Clone, Serialize)] +#[derive(Clone, Copy, Serialize)] pub struct LogicalVec2 { pub inline: T, pub block: T, @@ -117,6 +117,34 @@ where } } +impl AddAssign> for LogicalVec2 +where + T: AddAssign + Copy, +{ + fn add_assign(&mut self, other: LogicalVec2) { + self.add_assign(&other); + } +} + +impl SubAssign<&'_ LogicalVec2> for LogicalVec2 +where + T: SubAssign + Copy, +{ + fn sub_assign(&mut self, other: &'_ LogicalVec2) { + self.inline -= other.inline; + self.block -= other.block; + } +} + +impl SubAssign> for LogicalVec2 +where + T: SubAssign + Copy, +{ + fn sub_assign(&mut self, other: LogicalVec2) { + self.sub_assign(&other); + } +} + impl LogicalVec2 { pub fn zero() -> Self { Self { @@ -126,8 +154,8 @@ impl LogicalVec2 { } } -impl LogicalVec2 { - pub fn auto_is(&self, f: impl Fn() -> Length) -> LogicalVec2 { +impl LogicalVec2> { + pub fn auto_is(&self, f: impl Fn() -> T) -> LogicalVec2 { self.map(|t| t.auto_is(&f)) } } @@ -335,8 +363,8 @@ impl LogicalSides> { } } -impl LogicalSides { - pub fn auto_is(&self, f: impl Fn() -> Length) -> LogicalSides { +impl LogicalSides> { + pub fn auto_is(&self, f: impl Fn() -> T) -> LogicalSides { self.map(|s| s.auto_is(&f)) } } diff --git a/components/layout_2020/lists.rs b/components/layout_2020/lists.rs index f3ffe471a3e..1b337ac3555 100644 --- a/components/layout_2020/lists.rs +++ b/components/layout_2020/lists.rs @@ -2,6 +2,7 @@ * 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 log::warn; use style::properties::longhands::list_style_type::computed_value::T as ListStyleType; use style::properties::style_structs; use style::values::computed::Image; @@ -20,12 +21,19 @@ where Node: NodeExt<'dom>, { let style = info.style.get_list(); + let node = match info.node { + Some(node) => node, + None => { + warn!("Tried to make a marker for an anonymous node!"); + return None; + }, + }; // https://drafts.csswg.org/css-lists/#marker-image let marker_image = || match &style.list_style_image { Image::Url(url) => Some(vec![ PseudoElementContentItem::Replaced(ReplacedContent::from_image_url( - info.node, context, url, + node, context, url, )?), PseudoElementContentItem::Text(" ".into()), ]), diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 23964bea93b..256ab92897d 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -124,7 +124,7 @@ impl PositioningContext { } } - /// Create a [PositioninContext] to use for laying out a subtree. The idea is that + /// Create a [PositioningContext] to use for laying out a subtree. The idea is that /// when subtree layout is finished, the newly hoisted boxes can be processed /// (normally adjusting their static insets) and then appended to the parent /// [PositioningContext]. @@ -182,7 +182,7 @@ impl PositioningContext { self.adjust_static_position_of_hoisted_fragments_with_offset(start_offset, index); } - /// See documentation for [adjust_static_position_of_hoisted_fragments]. + /// See documentation for [PositioningContext::adjust_static_position_of_hoisted_fragments]. pub(crate) fn adjust_static_position_of_hoisted_fragments_with_offset( &mut self, start_offset: &LogicalVec2, @@ -388,7 +388,7 @@ impl PositioningContext { /// Truncate this [PositioningContext] to the given [PositioningContextLength]. This /// is useful for "unhoisting" boxes in this context and returning it to the state at - /// the time that [`len()`] was called. + /// the time that [`PositioningContext::len()`] was called. pub(crate) fn truncate(&mut self, length: &PositioningContextLength) { if let Some(vec) = self.for_nearest_positioned_ancestor.as_mut() { vec.truncate(length.for_nearest_positioned_ancestor); @@ -504,8 +504,8 @@ impl HoistedAbsolutelyPositionedBox { let inline_axis_solver = AbsoluteAxisSolver { containing_size: cbis, padding_border_sum: pbm.padding_border_sums.inline, - computed_margin_start: pbm.margin.inline_start.map(|t| t.into()), - computed_margin_end: pbm.margin.inline_end.map(|t| t.into()), + computed_margin_start: pbm.margin.inline_start, + computed_margin_end: pbm.margin.inline_end, avoid_negative_margin_start: true, box_offsets: &shared_fragment.box_offsets.inline, }; @@ -513,8 +513,8 @@ impl HoistedAbsolutelyPositionedBox { let block_axis_solver = AbsoluteAxisSolver { containing_size: cbbs, padding_border_sum: pbm.padding_border_sums.block, - computed_margin_start: pbm.margin.block_start.map(|t| t.into()), - computed_margin_end: pbm.margin.block_end.map(|t| t.into()), + computed_margin_start: pbm.margin.block_start, + computed_margin_end: pbm.margin.block_end, avoid_negative_margin_start: false, box_offsets: &shared_fragment.box_offsets.block, }; diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index e7e8cdf8667..c4cab2c0b13 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -505,12 +505,9 @@ fn process_offset_parent_query_inner( // "If any of the following holds true return null and terminate // this algorithm: [...] The element’s computed value of the // `position` property is `fixed`." - let is_fixed = match fragment { - Fragment::Box(fragment) if fragment.style.get_box().position == Position::Fixed => { - true - }, - _ => false, - }; + let is_fixed = matches!( + fragment, Fragment::Box(fragment) if fragment.style.get_box().position == Position::Fixed + ); if is_body_element { // "If the element is the HTML body element or [...] return zero diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index b4a5325eaca..243b6bf3083 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -13,16 +13,16 @@ use style::properties::longhands::column_span::computed_value::T as ColumnSpan; use style::properties::ComputedValues; use style::values::computed::image::Image as ComputedImageLayer; use style::values::computed::{Length, LengthPercentage, NonNegativeLengthPercentage, Size}; -use style::values::generics::box_::{GenericVerticalAlign, Perspective, VerticalAlignKeyword}; +use style::values::generics::box_::Perspective; use style::values::generics::length::MaxSize; -use style::values::specified::box_::DisplayOutside as StyloDisplayOutside; use style::values::specified::{box_ as stylo, Overflow}; use style::Zero; use webrender_api as wr; use crate::dom_traversal::Contents; use crate::geom::{ - LengthOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize, + AuOrAuto, LengthOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, + PhysicalSize, }; use crate::ContainingBlock; @@ -88,6 +88,7 @@ pub(crate) enum DisplayInside { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[allow(clippy::enum_variant_names)] /// pub(crate) enum DisplayLayoutInternal { TableCaption, @@ -117,7 +118,7 @@ impl DisplayLayoutInternal { pub(crate) struct PaddingBorderMargin { pub padding: LogicalSides, pub border: LogicalSides, - pub margin: LogicalSides, + pub margin: LogicalSides, /// Pre-computed sums in each axis pub padding_border_sums: LogicalVec2, @@ -187,7 +188,6 @@ pub(crate) trait ComputedValuesExt { fn establishes_containing_block_for_all_descendants(&self) -> bool; fn background_is_transparent(&self) -> bool; fn get_webrender_primitive_flags(&self) -> wr::PrimitiveFlags; - fn effective_vertical_align_for_inline_layout(&self) -> GenericVerticalAlign; } impl ComputedValuesExt for ComputedValues { @@ -350,6 +350,9 @@ impl ComputedValuesExt for ComputedValues { .padding(containing_block.style.writing_mode) .percentages_relative_to(cbis.into()); let border = self.border_width(containing_block.style.writing_mode); + let margin = self + .margin(containing_block.style.writing_mode) + .percentages_relative_to(cbis.into()); PaddingBorderMargin { padding_border_sums: LogicalVec2 { inline: (padding.inline_sum() + border.inline_sum()).into(), @@ -357,9 +360,7 @@ impl ComputedValuesExt for ComputedValues { }, padding: padding.into(), border: border.into(), - margin: self - .margin(containing_block.style.writing_mode) - .percentages_relative_to(cbis.into()), + margin: margin.map(|t| t.map(|m| m.into())), } } @@ -557,18 +558,6 @@ impl ComputedValuesExt for ComputedValues { BackfaceVisiblity::Hidden => wr::PrimitiveFlags::empty(), } } - - /// Get the effective `vertical-align` property for inline layout. Essentially, if this style - /// has outside block display, this is the inline formatting context root and `vertical-align` - /// doesn't come into play for inline layout. - fn effective_vertical_align_for_inline_layout(&self) -> GenericVerticalAlign { - match self.clone_display().outside() { - StyloDisplayOutside::Block => { - GenericVerticalAlign::Keyword(VerticalAlignKeyword::Baseline) - }, - _ => self.clone_vertical_align(), - } - } } impl From for Display { diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index fc9d3c3406b..79b6ad6f44b 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -26,7 +26,7 @@ use crate::formatting_contexts::{ IndependentFormattingContext, NonReplacedFormattingContext, NonReplacedFormattingContextContents, }; -use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag}; +use crate::fragment_tree::BaseFragmentInfo; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; /// A reference to a slot and its coordinates in the table @@ -84,12 +84,10 @@ impl Table { .stylist .style_for_anonymous::( &context.shared_context().guards, - // TODO: This should be updated for Layout 2020 once we've determined - // which styles should be inherited for tables. - &PseudoElement::ServoLegacyAnonymousTable, + &PseudoElement::ServoAnonymousTable, &parent_info.style, ); - let anonymous_info = parent_info.new_replacing_style(anonymous_style.clone()); + let anonymous_info = parent_info.new_anonymous(anonymous_style.clone()); let mut table_builder = TableBuilderTraversal::new(context, &anonymous_info, propagated_text_decoration_line); @@ -641,10 +639,10 @@ where .stylist .style_for_anonymous::( &context.shared_context().guards, - &PseudoElement::ServoAnonymousTableCell, + &PseudoElement::ServoAnonymousTableRow, &self.info.style, ); - let anonymous_info = self.info.new_replacing_style(anonymous_style); + let anonymous_info = self.info.new_anonymous(anonymous_style.clone()); let mut row_builder = TableRowBuilder::new(self, &anonymous_info, self.current_text_decoration_line); @@ -665,6 +663,23 @@ where } row_builder.finish(); + + self.push_table_row(TableTrack { + base_fragment_info: (&anonymous_info).into(), + style: anonymous_style, + group_index: self.current_row_group_index, + is_anonymous: true, + }); + } + + fn push_table_row(&mut self, table_track: TableTrack) { + self.builder.table.rows.push(table_track); + + let last_row = self.builder.table.rows.len(); + if let Some(index) = self.current_row_group_index { + let row_group = &mut self.builder.table.row_groups[index]; + row_group.track_range.end = last_row; + } } } @@ -706,8 +721,7 @@ where }); let previous_text_decoration_line = self.current_text_decoration_line; - self.current_text_decoration_line = - self.current_text_decoration_line | info.style.clone_text_decoration_line(); + self.current_text_decoration_line |= info.style.clone_text_decoration_line(); let new_row_group_index = self.builder.table.row_groups.len() - 1; self.current_row_group_index = Some(new_row_group_index); @@ -717,6 +731,7 @@ where info, self, ); + self.finish_anonymous_row_if_needed(); self.current_row_group_index = None; self.current_text_decoration_line = previous_text_decoration_line; @@ -739,27 +754,23 @@ where ); row_builder.finish(); - self.builder.table.rows.push(TableTrack { + self.push_table_row(TableTrack { base_fragment_info: info.into(), style: info.style.clone(), group_index: self.current_row_group_index, is_anonymous: false, }); - let last_row = self.builder.table.rows.len(); - let row_group = self - .current_row_group_index - .map(|index| &mut self.builder.table.row_groups[index]); - if let Some(row_group) = row_group { - row_group.track_range.end = last_row; - } - // We are doing this until we have actually set a Box for this `BoxSlot`. ::std::mem::forget(box_slot) }, DisplayLayoutInternal::TableColumn => { - let node = info.node.to_threadsafe(); - let span = (node.get_span().unwrap_or(1) as usize).min(1000); + let span = info + .node + .and_then(|node| node.to_threadsafe().get_span()) + .unwrap_or(1) + .min(1000); + for _ in 0..span + 1 { self.builder.table.columns.push(TableTrack { base_fragment_info: info.into(), @@ -787,8 +798,11 @@ where let first_column = self.builder.table.columns.len(); if column_group_builder.columns.is_empty() { - let node = info.node.to_threadsafe(); - let span = (node.get_span().unwrap_or(1) as usize).min(1000); + let span = info + .node + .and_then(|node| node.to_threadsafe().get_span()) + .unwrap_or(1) + .min(1000) as usize; self.builder.table.columns.extend( repeat(TableTrack { @@ -896,7 +910,7 @@ where &PseudoElement::ServoAnonymousTableCell, &self.info.style, ); - let anonymous_info = self.info.new_replacing_style(anonymous_style); + let anonymous_info = self.info.new_anonymous(anonymous_style); let mut builder = BlockContainerBuilder::new(context, &anonymous_info, self.text_decoration_line); @@ -916,22 +930,13 @@ where } } - let tag = Tag::new_pseudo( - self.info.node.opaque(), - Some(PseudoElement::ServoAnonymousTableCell), - ); - let base_fragment_info = BaseFragmentInfo { - tag, - flags: FragmentFlags::empty(), - }; - let block_container = builder.finish(); self.table_traversal.builder.add_cell(TableSlotCell { contents: BlockFormattingContext::from_block_container(block_container), colspan: 1, rowspan: 1, style: anonymous_info.style, - base_fragment_info, + base_fragment_info: BaseFragmentInfo::anonymous(), }); } } @@ -957,6 +962,7 @@ where contents: Contents, box_slot: BoxSlot<'dom>, ) { + #[allow(clippy::collapsible_match)] //// TODO: Remove once the other cases are handled match display { DisplayGeneratingBox::LayoutInternal(internal) => match internal { DisplayLayoutInternal::TableCell => { @@ -967,9 +973,12 @@ where // 65534 and `colspan` to 1000, so we also enforce the same limits // when dealing with arbitrary DOM elements (perhaps created via // script). - let node = info.node.to_threadsafe(); - let rowspan = (node.get_rowspan().unwrap_or(1) as usize).min(65534); - let colspan = (node.get_colspan().unwrap_or(1) as usize).min(1000); + let (rowspan, colspan) = info.node.map_or((1, 1), |node| { + let node = node.to_threadsafe(); + let rowspan = node.get_rowspan().unwrap_or(1).min(65534) as usize; + let colspan = node.get_colspan().unwrap_or(1).min(1000) as usize; + (rowspan, colspan) + }); let contents = match contents.try_into() { Ok(non_replaced_contents) => { diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 05501724c5e..e7f2c9f63f5 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -9,6 +9,7 @@ use log::warn; use servo_arc::Arc; use style::computed_values::border_collapse::T as BorderCollapse; use style::logical_geometry::WritingMode; +use style::properties::longhands::box_sizing::computed_value::T as BoxSizing; use style::properties::ComputedValues; use style::values::computed::{ CSSPixelLength, Length, LengthPercentage as ComputedLengthPercentage, Percentage, @@ -17,14 +18,15 @@ use style::values::generics::box_::{GenericVerticalAlign as VerticalAlign, Verti use style::values::generics::length::GenericLengthPercentageOrAuto::{Auto, LengthPercentage}; use style::Zero; -use super::{Table, TableSlot, TableSlotCell, TableTrackGroup}; +use super::{Table, TableSlot, TableSlotCell, TableTrack, TableTrackGroup}; use crate::context::LayoutContext; use crate::formatting_contexts::{Baselines, IndependentLayout}; use crate::fragment_tree::{ - BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment, PositioningFragment, + BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment, + PositioningFragment, }; use crate::geom::{AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2}; -use crate::positioned::{PositioningContext, PositioningContextLength}; +use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength}; use crate::sizing::ContentSizes; use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::table::TableSlotCoordinates; @@ -72,7 +74,7 @@ struct ColumnLayout { /// A helper struct that performs the layout of the box tree version /// of a table into the fragment tree version. This implements /// -struct TableLayout<'a> { +pub(crate) struct TableLayout<'a> { table: &'a Table, pbm: PaddingBorderMargin, rows: Vec, @@ -83,6 +85,7 @@ struct TableLayout<'a> { column_measures: Vec, distributed_column_widths: Vec, row_sizes: Vec, + /// The accumulated baseline of each row, relative to the top of the row. row_baselines: Vec, cells_laid_out: Vec>>, basis_for_cell_padding_percentage: Au, @@ -143,11 +146,24 @@ impl<'a> TableLayout<'a> { _ => continue, }; - let (size, min_size, max_size) = get_sizes_from_style(&cell.style, writing_mode); + let padding = cell + .style + .padding(writing_mode) + .percentages_relative_to(Length::zero()); + let border = cell.style.border_width(writing_mode); + let padding_border_sums = LogicalVec2 { + inline: (padding.inline_sum() + border.inline_sum()).into(), + block: (padding.block_sum() + border.block_sum()).into(), + }; + + let (size, min_size, max_size) = + get_outer_sizes_from_style(&cell.style, writing_mode, &padding_border_sums); let mut inline_content_sizes = cell .contents .contents .inline_content_sizes(layout_context, writing_mode); + inline_content_sizes.min_content += padding_border_sums.inline; + inline_content_sizes.max_content += padding_border_sums.inline; // TODO: the max-content size should never be smaller than the min-content size! inline_content_sizes.max_content = inline_content_sizes @@ -158,11 +174,11 @@ impl<'a> TableLayout<'a> { get_size_percentage_contribution_from_style(&cell.style, writing_mode); // These formulas differ from the spec, but seem to match Gecko and Blink. - let mut outer_min_content_width = inline_content_sizes + let outer_min_content_width = inline_content_sizes .min_content .min(max_size.inline) .max(min_size.inline); - let mut outer_max_content_width = if self.columns[column_index].constrained { + let outer_max_content_width = if self.columns[column_index].constrained { inline_content_sizes .min_content .max(size.inline) @@ -177,17 +193,6 @@ impl<'a> TableLayout<'a> { }; assert!(outer_min_content_width <= outer_max_content_width); - let padding = cell - .style - .padding(writing_mode) - .percentages_relative_to(Length::zero()); - let border = cell.style.border_width(writing_mode); - - let inline_padding_border_sum = - Au::from(padding.inline_sum() + border.inline_sum()); - outer_min_content_width += inline_padding_border_sum; - outer_max_content_width += inline_padding_border_sum; - let inline_measure = CellOrTrackMeasure { content_sizes: ContentSizes { min_content: outer_min_content_width, @@ -196,31 +201,13 @@ impl<'a> TableLayout<'a> { percentage: percentage_contribution.inline, }; - // These calculations do not take into account the `min-content` and `max-content` - // sizes. These sizes are incorporated after the first row layout pass, when the - // block size of the layout is known. - // - // TODO: Is it correct to use the block size as the minimum of the `outer min - // content height` here? The specification doesn't mention this, but it does cause - // a test to pass. - let mut outer_min_content_height = min_size.block.max(size.block); - let mut outer_max_content_height = if !self.rows[row_index].constrained { - min_size.block.max(size.block) - } else { - min_size - .block - .max(size.block) - .max(max_size.block.min(size.block)) - }; - - let block_padding_border_sum = Au::from(padding.block_sum() + border.block_sum()); - outer_min_content_height += block_padding_border_sum; - outer_max_content_height += block_padding_border_sum; - + // This measure doesn't take into account the `min-content` and `max-content` sizes. + // These sizes are incorporated after the first row layout pass, when the block size + // of the layout is known. let block_measure = CellOrTrackMeasure { content_sizes: ContentSizes { - min_content: outer_min_content_height, - max_content: outer_max_content_height, + min_content: size.block, + max_content: size.block, }, percentage: percentage_contribution.block, }; @@ -389,8 +376,7 @@ impl<'a> TableLayout<'a> { // > * 100% minus the sum of the intrinsic percentage width of all prior columns in // > the table (further left when direction is "ltr" (right for "rtl")) let mut total_intrinsic_percentage_width = 0.; - for column_index in 0..self.table.size.width { - let column_measure = &mut column_measures[column_index]; + for column_measure in column_measures.iter_mut() { let final_intrinsic_percentage_width = column_measure .percentage .0 @@ -837,7 +823,7 @@ impl<'a> TableLayout<'a> { /// This is an implementation of *Distributing excess width to columns* from /// . - fn distribute_extra_width_to_columns(&self, column_sizes: &mut Vec, column_sizes_sum: Au) { + fn distribute_extra_width_to_columns(&self, column_sizes: &mut [Au], column_sizes_sum: Au) { let all_columns = 0..self.table.size.width; let extra_inline_size = self.assignable_width - column_sizes_sum; @@ -984,10 +970,26 @@ impl<'a> TableLayout<'a> { parent_positioning_context: &mut PositioningContext, ) { for row_index in 0..self.table.slots.len() { - let row = &self.table.slots[row_index]; + // When building the PositioningContext for this cell, we want it to have the same + // configuration for whatever PositioningContext the contents are ultimately added to. + let collect_for_nearest_positioned_ancestor = parent_positioning_context + .collects_for_nearest_positioned_ancestor() || + self.table.rows.get(row_index).map_or(false, |row| { + let row_group_collects_for_nearest_positioned_ancestor = + row.group_index.map_or(false, |group_index| { + self.table.row_groups[group_index] + .style + .establishes_containing_block_for_absolute_descendants() + }); + row_group_collects_for_nearest_positioned_ancestor || + row.style + .establishes_containing_block_for_absolute_descendants() + }); + let mut cells_laid_out_row = Vec::new(); - for column_index in 0..row.len() { - let cell = match &row[column_index] { + let slots = &self.table.slots[row_index]; + for (column_index, slot) in slots.iter().enumerate() { + let cell = match slot { TableSlot::Cell(cell) => cell, _ => { cells_laid_out_row.push(None); @@ -1017,8 +1019,7 @@ impl<'a> TableLayout<'a> { block_size: AuOrAuto::Auto, style: &cell.style, }; - let collect_for_nearest_positioned_ancestor = - parent_positioning_context.collects_for_nearest_positioned_ancestor(); + let mut positioning_context = PositioningContext::new_for_subtree(collect_for_nearest_positioned_ancestor); @@ -1103,6 +1104,7 @@ impl<'a> TableLayout<'a> { row_sizes } + #[allow(clippy::ptr_arg)] // Needs to be a vec because of the function above /// After doing layout of table rows, calculate final row size and distribute space across /// rowspanned cells. This follows the implementation of LayoutNG and the priority /// agorithm described at . @@ -1113,6 +1115,7 @@ impl<'a> TableLayout<'a> { ) { let mut cells_to_distribute = Vec::new(); let mut total_percentage = 0.; + #[allow(clippy::needless_range_loop)] // It makes sense to use it here for row_index in 0..self.table.size.height { let row_measure = self .table @@ -1201,7 +1204,7 @@ impl<'a> TableLayout<'a> { &self, mut excess_size: Au, track_range: Range, - track_sizes: &mut Vec, + track_sizes: &mut [Au], percentage_resolution_size: Option, rowspan_distribution: bool, ) { @@ -1412,21 +1415,52 @@ impl<'a> TableLayout<'a> { assert_eq!(self.table.size.width, self.distributed_column_widths.len()); let mut baselines = Baselines::default(); - let mut fragments = Vec::new(); + let mut table_fragments = Vec::new(); if self.table.size.width == 0 || self.table.size.height == 0 { return IndependentLayout { - fragments, + fragments: table_fragments, content_block_size: self.final_table_height, content_inline_size_for_table: Some(self.assignable_width), baselines, }; } - let dimensions = TableAndTrackDimensions::new(&self); - self.make_fragments_for_columns_rows_and_groups(&dimensions, &mut fragments); + let table_and_track_dimensions = TableAndTrackDimensions::new(&self); + self.make_fragments_for_columns_and_column_groups( + &table_and_track_dimensions, + &mut table_fragments, + ); + let mut row_group_fragment_layout = None; for row_index in 0..self.table.size.height { + let table_row = &self.table.rows[row_index]; + let mut row_fragment_layout = + RowFragmentLayout::new(table_row, row_index, &table_and_track_dimensions); + + let old_row_group_index = row_group_fragment_layout + .as_ref() + .map(|layout: &RowGroupFragmentLayout| layout.index); + if table_row.group_index != old_row_group_index { + // First create the Fragment for any existing RowGroupFragmentLayout. + if let Some(old_row_group_layout) = row_group_fragment_layout.take() { + table_fragments.push(Fragment::Box(old_row_group_layout.finish( + layout_context, + positioning_context, + containing_block_for_children, + ))); + } + + // Then, create a new RowGroupFragmentLayout for the current and potentially subsequent rows. + if let Some(new_group_index) = table_row.group_index { + row_group_fragment_layout = Some(RowGroupFragmentLayout::new( + &self.table.row_groups[new_group_index], + new_group_index, + &table_and_track_dimensions, + )); + } + } + // From // > If any cells in the row participate in first baseline/last baseline alignment along // > the inline axis, the first/last baseline set of the row is generated from their @@ -1437,86 +1471,57 @@ impl<'a> TableLayout<'a> { // If any cell below has baseline alignment, these values will be overwritten, // but they are initialized to the content edge of the first row. if row_index == 0 { - let row_end = dimensions.get_row_rect(0).max_block_position(); + let row_end = table_and_track_dimensions + .get_row_rect(0) + .max_block_position(); baselines.first = Some(row_end); baselines.last = Some(row_end); } - for column_index in 0..self.table.size.width { - let layout = match self.cells_laid_out[row_index][column_index].take() { - Some(layout) => layout, - None => { - continue; - }, - }; + let column_indices = 0..self.table.size.width.clone(); + row_fragment_layout.fragments.reserve(self.table.size.width); + for column_index in column_indices { + // The PositioningContext for cells is, in order or preference, the PositioningContext of the row, + // the PositioningContext of the row group, or the PositioningContext of the table. + let row_group_positioning_context = row_group_fragment_layout + .as_mut() + .and_then(|layout| layout.positioning_context.as_mut()); + let positioning_context_for_cells = row_fragment_layout + .positioning_context + .as_mut() + .or(row_group_positioning_context) + .unwrap_or(positioning_context); - let cell = match self.table.slots[row_index][column_index] { - TableSlot::Cell(ref cell) => cell, - _ => { - warn!("Did not find a non-spanned cell at index with layout."); - continue; - }, - }; - - let cell_rect = dimensions.get_cell_rect( - TableSlotCoordinates::new(column_index, row_index), - cell.rowspan, - cell.colspan, + self.do_final_cell_layout( + row_index, + column_index, + &table_and_track_dimensions, + &row_fragment_layout.rect, + positioning_context_for_cells, + &mut baselines, + &mut row_fragment_layout.fragments, ); - - // If this cell has baseline alignment, it can adjust the table's overall baseline. - let row_baseline = self.row_baselines[row_index]; - if cell.effective_vertical_align() == VerticalAlignKeyword::Baseline { - let baseline = cell_rect.start_corner.block + row_baseline; - if row_index == 0 { - baselines.first = Some(baseline); - } - baselines.last = Some(baseline); - } - - let mut fragment = - cell.create_fragment(layout, cell_rect, row_baseline, positioning_context); - - let column = self.table.columns.get(column_index); - let column_group = column - .and_then(|column| column.group_index) - .and_then(|index| self.table.column_groups.get(index)); - if let Some(column_group) = column_group { - fragment.add_extra_background(ExtraBackground { - style: column_group.style.clone(), - rect: dimensions.get_column_group_rect(column_group), - }) - } - - if let Some(column) = column { - if !column.is_anonymous { - fragment.add_extra_background(ExtraBackground { - style: column.style.clone(), - rect: dimensions.get_column_rect(column_index), - }) - } - } - - let row = self.table.rows.get(row_index); - let row_group = row - .and_then(|row| row.group_index) - .and_then(|index| self.table.row_groups.get(index)); - if let Some(row_group) = row_group { - fragment.add_extra_background(ExtraBackground { - style: row_group.style.clone(), - rect: dimensions.get_row_group_rect(row_group), - }) - } - - if let Some(row) = row { - fragment.add_extra_background(ExtraBackground { - style: row.style.clone(), - rect: dimensions.get_row_rect(row_index), - }) - } - - fragments.push(Fragment::Box(fragment)); } + + let row_fragment = Fragment::Box(row_fragment_layout.finish( + layout_context, + positioning_context, + containing_block_for_children, + &mut row_group_fragment_layout, + )); + + match row_group_fragment_layout.as_mut() { + Some(layout) => layout.fragments.push(row_fragment), + None => table_fragments.push(row_fragment), + } + } + + if let Some(row_group_layout) = row_group_fragment_layout.take() { + table_fragments.push(Fragment::Box(row_group_layout.finish( + layout_context, + positioning_context, + containing_block_for_children, + ))); } if self.table.anonymous { @@ -1525,14 +1530,109 @@ impl<'a> TableLayout<'a> { } IndependentLayout { - fragments, - content_block_size: dimensions.table_rect.max_block_position(), - content_inline_size_for_table: Some(dimensions.table_rect.max_inline_position()), + fragments: table_fragments, + content_block_size: table_and_track_dimensions.table_rect.max_block_position(), + content_inline_size_for_table: Some( + table_and_track_dimensions.table_rect.max_inline_position(), + ), baselines, } } - fn make_fragments_for_columns_rows_and_groups( + fn do_final_cell_layout( + &mut self, + row_index: usize, + column_index: usize, + dimensions: &TableAndTrackDimensions, + row_rect: &LogicalRect, + positioning_context: &mut PositioningContext, + baselines: &mut Baselines, + cell_fragments: &mut Vec, + ) { + let layout = match self.cells_laid_out[row_index][column_index].take() { + Some(layout) => layout, + None => { + return; + }, + }; + let cell = match self.table.slots[row_index][column_index] { + TableSlot::Cell(ref cell) => cell, + _ => { + warn!("Did not find a non-spanned cell at index with layout."); + return; + }, + }; + + let row_block_offset = row_rect.start_corner.block; + let row_baseline = self.row_baselines[row_index]; + if cell.effective_vertical_align() == VerticalAlignKeyword::Baseline { + let baseline = row_block_offset + row_baseline; + if row_index == 0 { + baselines.first = Some(baseline); + } + baselines.last = Some(baseline); + } + let mut row_relative_cell_rect = dimensions.get_cell_rect( + TableSlotCoordinates::new(column_index, row_index), + cell.rowspan, + cell.colspan, + ); + row_relative_cell_rect.start_corner = + &row_relative_cell_rect.start_corner - &row_rect.start_corner; + let mut fragment = cell.create_fragment( + layout, + row_relative_cell_rect, + row_baseline, + positioning_context, + ); + let column = self.table.columns.get(column_index); + let column_group = column + .and_then(|column| column.group_index) + .and_then(|index| self.table.column_groups.get(index)); + if let Some(column_group) = column_group { + let mut rect = dimensions.get_column_group_rect(column_group); + rect.start_corner -= row_rect.start_corner; + fragment.add_extra_background(ExtraBackground { + style: column_group.style.clone(), + rect, + }) + } + if let Some(column) = column { + if !column.is_anonymous { + let mut rect = dimensions.get_column_rect(column_index); + rect.start_corner -= row_rect.start_corner; + fragment.add_extra_background(ExtraBackground { + style: column.style.clone(), + rect, + }) + } + } + let row = self.table.rows.get(row_index); + let row_group = row + .and_then(|row| row.group_index) + .and_then(|index| self.table.row_groups.get(index)); + if let Some(row_group) = row_group { + let mut rect = dimensions.get_row_group_rect(row_group); + rect.start_corner -= row_rect.start_corner; + fragment.add_extra_background(ExtraBackground { + style: row_group.style.clone(), + rect, + }) + } + if let Some(row) = row { + let mut rect = row_rect.clone(); + rect.start_corner = LogicalVec2::zero(); + fragment.add_extra_background(ExtraBackground { + style: row.style.clone(), + rect, + }) + } + cell_fragments.push(Fragment::Box(fragment)); + + // If this cell has baseline alignment, it can adjust the table's overall baseline. + } + + fn make_fragments_for_columns_and_column_groups( &mut self, dimensions: &TableAndTrackDimensions, fragments: &mut Vec, @@ -1554,27 +1654,129 @@ impl<'a> TableLayout<'a> { column.style.clone(), ))); } - - for row_group in self.table.row_groups.iter() { - if !row_group.is_empty() { - fragments.push(Fragment::Positioning(PositioningFragment::new_empty( - row_group.base_fragment_info, - dimensions.get_row_group_rect(row_group).into(), - row_group.style.clone(), - ))); - } - } - - for (row_index, row) in self.table.rows.iter().enumerate() { - fragments.push(Fragment::Positioning(PositioningFragment::new_empty( - row.base_fragment_info, - dimensions.get_row_rect(row_index).into(), - row.style.clone(), - ))); - } } } +struct RowFragmentLayout<'a> { + row: &'a TableTrack, + rect: LogicalRect, + positioning_context: Option, + fragments: Vec, +} + +impl<'a> RowFragmentLayout<'a> { + fn new(table_row: &'a TableTrack, index: usize, dimensions: &TableAndTrackDimensions) -> Self { + Self { + row: table_row, + rect: dimensions.get_row_rect(index), + positioning_context: PositioningContext::new_for_style(&table_row.style), + fragments: Vec::new(), + } + } + fn finish( + mut self, + layout_context: &LayoutContext, + table_positioning_context: &mut PositioningContext, + containing_block: &ContainingBlock, + row_group_fragment_layout: &mut Option, + ) -> BoxFragment { + let mut row_rect: LogicalRect = self.rect.into(); + if self.positioning_context.is_some() { + row_rect.start_corner += relative_adjustement(&self.row.style, containing_block); + } + + if let Some(ref row_group_layout) = row_group_fragment_layout { + let row_group_start_corner: LogicalVec2 = + row_group_layout.rect.start_corner.into(); + row_rect.start_corner -= row_group_start_corner; + } + + let mut row_fragment = BoxFragment::new( + self.row.base_fragment_info, + self.row.style.clone(), + self.fragments, + row_rect, + LogicalSides::zero(), /* padding */ + LogicalSides::zero(), /* border */ + LogicalSides::zero(), /* margin */ + None, /* clearance */ + CollapsedBlockMargins::zero(), + ); + row_fragment.set_does_not_paint_background(); + + if let Some(mut row_positioning_context) = self.positioning_context.take() { + row_positioning_context.layout_collected_children(layout_context, &mut row_fragment); + + let positioning_context = row_group_fragment_layout + .as_mut() + .and_then(|layout| layout.positioning_context.as_mut()) + .unwrap_or(table_positioning_context); + positioning_context.append(row_positioning_context); + } + + row_fragment + } +} + +struct RowGroupFragmentLayout { + base_fragment_info: BaseFragmentInfo, + style: Arc, + rect: LogicalRect, + positioning_context: Option, + index: usize, + fragments: Vec, +} + +impl RowGroupFragmentLayout { + fn new( + row_group: &TableTrackGroup, + index: usize, + dimensions: &TableAndTrackDimensions, + ) -> Self { + let rect = dimensions.get_row_group_rect(row_group); + Self { + base_fragment_info: row_group.base_fragment_info, + style: row_group.style.clone(), + rect, + positioning_context: PositioningContext::new_for_style(&row_group.style), + index, + fragments: Vec::new(), + } + } + + fn finish( + mut self, + layout_context: &LayoutContext, + table_positioning_context: &mut PositioningContext, + containing_block: &ContainingBlock, + ) -> BoxFragment { + let mut content_rect: LogicalRect = self.rect.into(); + if self.positioning_context.is_some() { + content_rect.start_corner += relative_adjustement(&self.style, containing_block); + } + + let mut row_group_fragment = BoxFragment::new( + self.base_fragment_info, + self.style, + self.fragments, + content_rect, + LogicalSides::zero(), /* padding */ + LogicalSides::zero(), /* border */ + LogicalSides::zero(), /* margin */ + None, /* clearance */ + CollapsedBlockMargins::zero(), + ); + row_group_fragment.set_does_not_paint_background(); + + if let Some(mut row_positioning_context) = self.positioning_context.take() { + row_positioning_context + .layout_collected_children(layout_context, &mut row_group_fragment); + table_positioning_context.append(row_positioning_context); + } + + row_group_fragment + } +} struct TableAndTrackDimensions { /// The rect of the full table, not counting for borders, padding, and margin. table_rect: LogicalRect, @@ -1743,7 +1945,8 @@ impl Table { None => return CellOrTrackMeasure::zero(), }; - let (size, min_size, max_size) = get_sizes_from_style(&column.style, writing_mode); + let (size, min_size, max_size) = + get_outer_sizes_from_style(&column.style, writing_mode, &LogicalVec2::zero()); let percentage_contribution = get_size_percentage_contribution_from_style(&column.style, writing_mode); @@ -1921,40 +2124,34 @@ fn get_size_percentage_contribution_from_style( } } -fn get_sizes_from_style( +fn get_outer_sizes_from_style( style: &Arc, writing_mode: WritingMode, + padding_border_sums: &LogicalVec2, ) -> (LogicalVec2, LogicalVec2, LogicalVec2) { - let get_max_size_for_axis = |size: Option<&ComputedLengthPercentage>| { - size.and_then(|length_percentage| length_percentage.to_length()) - .map_or(MAX_AU, Au::from) + let box_sizing = style.get_position().box_sizing; + let outer_size = |size: LogicalVec2| match box_sizing { + BoxSizing::ContentBox => &size + padding_border_sums, + BoxSizing::BorderBox => LogicalVec2 { + inline: size.inline.max(padding_border_sums.inline), + block: size.block.max(padding_border_sums.block), + }, }; - - let max_size = style.max_box_size(writing_mode); - let max_size = LogicalVec2 { - inline: get_max_size_for_axis(max_size.inline), - block: get_max_size_for_axis(max_size.block), - }; - - let get_size_for_axis = |size: LengthPercentageOrAuto<'_>| { + let get_size_for_axis = |size: &LengthPercentageOrAuto<'_>| { size.non_auto() .and_then(|size| size.to_length()) .map_or_else(Au::zero, Au::from) }; - - let min_size = style.min_box_size(writing_mode); - let min_size = LogicalVec2 { - inline: get_size_for_axis(min_size.inline), - block: get_size_for_axis(min_size.block), + let get_max_size_for_axis = |size: &Option<&ComputedLengthPercentage>| { + size.and_then(|length_percentage| length_percentage.to_length()) + .map_or(MAX_AU, Au::from) }; - let size = style.box_size(writing_mode); - let size = LogicalVec2 { - inline: get_size_for_axis(size.inline), - block: get_size_for_axis(size.block), - }; - - (size, min_size, max_size) + ( + outer_size(style.box_size(writing_mode).map(get_size_for_axis)), + outer_size(style.min_box_size(writing_mode).map(get_size_for_axis)), + outer_size(style.max_box_size(writing_mode).map(get_max_size_for_axis)), + ) } struct RowspanToDistribute<'a> { diff --git a/components/layout_2020/table/mod.rs b/components/layout_2020/table/mod.rs index f11016a8948..f3f0d676e7b 100644 --- a/components/layout_2020/table/mod.rs +++ b/components/layout_2020/table/mod.rs @@ -2,12 +2,67 @@ * 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/. */ -//! HTML Tables (╯°□°)╯︵ ┻━┻. +//! # HTML Tables (╯°□°)╯︵ ┻━┻ //! -//! See and -//! . This is heavily based on the latter specification, but -//! note that it is still an Editor's Draft, so there is no guarantee that what is implemented here -//! matches other browsers or the current specification. +//! This implementation is based on the [table section of the HTML 5 Specification][1], +//! the draft [CSS Table Module Level! 3][2] and the [LayoutNG implementation of tables][3] in Blink. +//! In general, the draft specification differs greatly from what other browsers do, so we +//! generally follow LayoutNG when in question. +//! +//! [1]: https://html.spec.whatwg.org/multipage/#tables +//! [2]: https://drafts.csswg.org/css-tables +//! [3]: https://source.chromium.org/chromium/chromium/src/third_party/+/main:blink/renderer/core/layout/table +//! +//! Table layout is divided into two phases: +//! +//! 1. Box Tree Construction +//! 2. Fragment Tree Construction +//! +//! ## Box Tree Construction +//! +//! During box tree construction, table layout (`construct.rs`) will traverse the DOM and construct +//! the basic box tree representation of a table, using the structs defined in this file ([`Table`], +//! [`TableTrackGroup`], [`TableTrack`], etc). When processing the DOM, elements are handled +//! differently depending on their `display` value. For instance, an element with `display: +//! table-cell` is treated as a table cell. HTML table elements like `` and `` +//! comes before `` which comes before the first ``. +//! +//! ## Fragment Tree Construction +//! +//! Fragment tree construction involves calculating the size and positioning of all table elements, +//! given their style, content, and cell and row spans. This happens both during intrinsic inline +//! size computation as well as layout into Fragments. In both of these cases, measurement and +//! layout is done by [`layout::TableLayout`], though for intrinsic size computation only a partial +//! layout is done. +//! +//! In general, we follow the following steps when laying out table content: +//! +//! 1. Compute track constrainedness and has originating cells +//! 2. Compute cell measures +//! 3. Compute column measures +//! 4. Compute intrinsic inline sizes for columns and the table +//! 5. Compute the final table inline size +//! 6. Distribute size to columns +//! 7. Do first pass cell layout +//! 8. Do row layout +//! 9. Compute table height and final row sizes +//! 10. Create fragments for table elements (columns, column groups, rows, row groups, cells) +//! +//! For intrinsic size computation this process stops at step 4. mod construct; mod layout; @@ -143,7 +198,7 @@ impl TableSlotCell { /// Get the node id of this cell's [`BaseFragmentInfo`]. This is used for unit tests. pub fn node_id(&self) -> usize { - self.base_fragment_info.tag.node.0 + self.base_fragment_info.tag.map_or(0, |tag| tag.node.0) } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 74be9d0cfd9..34d00ff03d5 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -295,43 +295,6 @@ impl<'a, 'b: 'a> RwData<'a, 'b> { } } -fn add_font_face_rules( - stylesheet: &Stylesheet, - guard: &SharedRwLockReadGuard, - device: &Device, - font_cache_thread: &FontCacheThread, - font_cache_sender: &IpcSender<()>, - outstanding_web_fonts_counter: &Arc, - load_webfonts_synchronously: bool, -) { - if load_webfonts_synchronously { - let (sender, receiver) = ipc::channel().unwrap(); - stylesheet.effective_font_face_rules(&device, guard, |rule| { - if let Some(font_face) = rule.font_face() { - let effective_sources = font_face.effective_sources(); - font_cache_thread.add_web_font( - font_face.family().clone(), - effective_sources, - sender.clone(), - ); - receiver.recv().unwrap(); - } - }) - } else { - stylesheet.effective_font_face_rules(&device, guard, |rule| { - if let Some(font_face) = rule.font_face() { - let effective_sources = font_face.effective_sources(); - outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); - font_cache_thread.add_web_font( - font_face.family().clone(), - effective_sources, - (*font_cache_sender).clone(), - ); - } - }) - } -} - impl Layout for LayoutThread { fn process(&mut self, msg: script_layout_interface::message::Msg) { self.handle_request(Request::FromScript(msg)); @@ -644,15 +607,16 @@ impl LayoutThread { // Find all font-face rules and notify the font cache of them. // GWTODO: Need to handle unloading web fonts. if stylesheet.is_effective_for_device(self.stylist.device(), &guard) { - add_font_face_rules( - &*stylesheet, - &guard, - self.stylist.device(), - &self.font_cache_thread, - &self.font_cache_sender, - &self.outstanding_web_fonts, - self.debug.load_webfonts_synchronously, - ); + let newly_loading_font_count = + self.font_cache_thread.add_all_web_fonts_from_stylesheet( + &*stylesheet, + &guard, + self.stylist.device(), + &self.font_cache_sender, + self.debug.load_webfonts_synchronously, + ); + self.outstanding_web_fonts + .fetch_add(newly_loading_font_count, Ordering::SeqCst); } } @@ -872,7 +836,7 @@ impl LayoutThread { self.epoch.set(epoch); // TODO: Avoid the temporary conversion and build webrender sc/dl directly! - let (builder, compositor_info, is_contentful) = + let (mut builder, compositor_info, is_contentful) = display_list.convert_to_webrender(self.id, viewport_size, epoch.into()); // Observe notifications about rendered frames if needed right before @@ -882,7 +846,7 @@ impl LayoutThread { .maybe_observe_paint_time(self, epoch, is_contentful.0); self.webrender_api - .send_display_list(compositor_info, builder.finalize().1); + .send_display_list(compositor_info, builder.end().1); }, ); } @@ -1281,7 +1245,7 @@ impl LayoutThread { // particular pipeline, so we need to tell WebRender about that. flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); - let client_point = units::WorldPoint::from_untyped(client_point); + let client_point = units::DevicePoint::from_untyped(client_point); let results = self.webrender_api.hit_test( Some(self.id.to_webrender()), client_point, @@ -1317,8 +1281,11 @@ impl LayoutThread { .insert(state.scroll_id, state.scroll_offset); let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); - self.webrender_api - .send_scroll_node(units::LayoutPoint::from_untyped(point), state.scroll_id); + self.webrender_api.send_scroll_node( + self.id.to_webrender(), + units::LayoutPoint::from_untyped(point), + state.scroll_id, + ); } fn set_scroll_states<'a, 'b>( diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index f3dd538adda..7c27b9a9212 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -273,42 +273,6 @@ impl<'a, 'b: 'a> RwData<'a, 'b> { } } -fn add_font_face_rules( - stylesheet: &Stylesheet, - guard: &SharedRwLockReadGuard, - device: &Device, - font_cache_thread: &FontCacheThread, - font_cache_sender: &IpcSender<()>, - outstanding_web_fonts_counter: &Arc, - load_webfonts_synchronously: bool, -) { - if load_webfonts_synchronously { - let (sender, receiver) = ipc::channel().unwrap(); - stylesheet.effective_font_face_rules(&device, guard, |rule| { - if let Some(font_face) = rule.font_face() { - let effective_sources = font_face.effective_sources(); - font_cache_thread.add_web_font( - font_face.family().clone(), - effective_sources, - sender.clone(), - ); - receiver.recv().unwrap(); - } - }) - } else { - stylesheet.effective_font_face_rules(&device, guard, |rule| { - if let Some(font_face) = rule.font_face() { - let effective_sources = font_face.effective_sources(); - outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); - font_cache_thread.add_web_font( - font_face.family().clone(), - effective_sources, - (*font_cache_sender).clone(), - ); - } - }) - } -} impl Layout for LayoutThread { fn process(&mut self, msg: script_layout_interface::message::Msg) { self.handle_request(Request::FromScript(msg)); @@ -578,15 +542,16 @@ impl LayoutThread { // Find all font-face rules and notify the font cache of them. // GWTODO: Need to handle unloading web fonts. if stylesheet.is_effective_for_device(self.stylist.device(), &guard) { - add_font_face_rules( - &*stylesheet, - &guard, - self.stylist.device(), - &self.font_cache_thread, - &self.font_cache_sender, - &self.outstanding_web_fonts, - self.debug.load_webfonts_synchronously, - ); + let newly_loading_font_count = + self.font_cache_thread.add_all_web_fonts_from_stylesheet( + &*stylesheet, + &guard, + self.stylist.device(), + &self.font_cache_sender, + self.debug.load_webfonts_synchronously, + ); + self.outstanding_web_fonts + .fetch_add(newly_loading_font_count, Ordering::SeqCst); } } @@ -951,7 +916,7 @@ impl LayoutThread { // particular pipeline, so we need to tell WebRender about that. flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); - let client_point = units::WorldPoint::from_untyped(client_point); + let client_point = units::DevicePoint::from_untyped(client_point); let results = self.webrender_api.hit_test( Some(self.id.to_webrender()), client_point, @@ -984,8 +949,11 @@ impl LayoutThread { .insert(state.scroll_id, state.scroll_offset); let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); - self.webrender_api - .send_scroll_node(units::LayoutPoint::from_untyped(point), state.scroll_id); + self.webrender_api.send_scroll_node( + self.id.to_webrender(), + units::LayoutPoint::from_untyped(point), + state.scroll_id, + ); } fn set_scroll_states<'a, 'b>( @@ -1061,7 +1029,9 @@ impl LayoutThread { fragment_tree.scrollable_overflow(), self.id.to_webrender(), epoch.into(), + fragment_tree.root_scroll_sensitivity, ); + display_list.wr.begin(); // `dump_serialized_display_list` doesn't actually print anything. It sets up // the display list for printing the serialized version when `finalize()` is called. @@ -1097,7 +1067,7 @@ impl LayoutThread { if reflow_goal.needs_display() { self.webrender_api - .send_display_list(display_list.compositor_info, display_list.wr.finalize().1); + .send_display_list(display_list.compositor_info, display_list.wr.end().1); } self.update_iframe_sizes(iframe_sizes); diff --git a/components/media/lib.rs b/components/media/lib.rs index e746d668ba1..f29493eb4b3 100644 --- a/components/media/lib.rs +++ b/components/media/lib.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #![deny(unsafe_code)] +#![allow(clippy::type_complexity)] mod media_channel; mod media_thread; diff --git a/components/media/media_channel/mod.rs b/components/media/media_channel/mod.rs index 21586e0456e..00259e4e499 100644 --- a/components/media/media_channel/mod.rs +++ b/components/media/media_channel/mod.rs @@ -74,6 +74,7 @@ where } } + #[allow(clippy::wrong_self_convention)] // It is an alias to the underlying module pub fn to_opaque(self) -> ipc_channel::ipc::OpaqueIpcReceiver { match self { GLPlayerReceiver::Ipc(receiver) => receiver.to_opaque(), diff --git a/components/media/media_thread.rs b/components/media/media_thread.rs index c6cf45dbe2d..9bd556d6b72 100644 --- a/components/media/media_thread.rs +++ b/components/media/media_thread.rs @@ -79,14 +79,14 @@ impl GLPlayerThread { } }, GLPlayerMsg::Lock(id, handler_sender) => { - self.players.get(&id).map(|sender| { + if let Some(sender) = self.players.get(&id) { sender.send(GLPlayerMsgForward::Lock(handler_sender)).ok(); - }); + } }, GLPlayerMsg::Unlock(id) => { - self.players.get(&id).map(|sender| { + if let Some(sender) = self.players.get(&id) { sender.send(GLPlayerMsgForward::Unlock()).ok(); - }); + } }, GLPlayerMsg::Exit => return true, } diff --git a/components/metrics/lib.rs b/components/metrics/lib.rs index 971ad729441..7aa42f365ae 100644 --- a/components/metrics/lib.rs +++ b/components/metrics/lib.rs @@ -75,13 +75,7 @@ fn set_metric( pwm.send_queued_constellation_msg(metric_type, time); // Send the metric to the time profiler. - send_profile_data( - category, - metadata, - &pwm.get_time_profiler_chan(), - time, - time, - ); + send_profile_data(category, metadata, pwm.get_time_profiler_chan(), time, time); // Print the metric to console if the print-pwm option was given. if opts::get().print_pwm { @@ -119,13 +113,15 @@ pub struct InteractiveWindow { start: SystemTime, } -impl InteractiveWindow { - pub fn new() -> InteractiveWindow { - InteractiveWindow { +impl Default for InteractiveWindow { + fn default() -> Self { + Self { start: SystemTime::now(), } } +} +impl InteractiveWindow { // We need to either start or restart the 10s window // start: we've added a new document // restart: there was a task > 50ms @@ -163,7 +159,7 @@ impl InteractiveMetrics { dom_content_loaded: Cell::new(None), main_thread_available: Cell::new(None), time_to_interactive: Cell::new(None), - time_profiler_chan: time_profiler_chan, + time_profiler_chan, url, } } diff --git a/components/net/connector.rs b/components/net/connector.rs index 8adb7f74696..003576d1462 100644 --- a/components/net/connector.rs +++ b/components/net/connector.rs @@ -54,7 +54,7 @@ impl Service for ServoHttpConnector { let authority = if let Some(port) = auth.port() { format!("{}:{}", host, port.as_str()) } else { - format!("{}", &*host) + (*host).to_string() }; if let Ok(authority) = Authority::from_maybe_shared(authority) { diff --git a/components/net/cookie.rs b/components/net/cookie.rs index 7ce8e1d6ddf..e6f348249bd 100644 --- a/components/net/cookie.rs +++ b/components/net/cookie.rs @@ -106,8 +106,8 @@ impl Cookie { "" }) .to_owned(); - if path.chars().next() != Some('/') { - path = Cookie::default_path(&request.path().to_owned()).to_string(); + if !path.starts_with('/') { + path = Cookie::default_path(request.path()).to_string(); } cookie.set_path(path); @@ -152,12 +152,12 @@ impl Cookie { // http://tools.ietf.org/html/rfc6265#section-5.1.4 pub fn default_path(request_path: &str) -> &str { // Step 2 - if request_path.chars().next() != Some('/') { + if !request_path.starts_with('/') { return "/"; } // Step 3 - let rightmost_slash_idx = request_path.rfind("/").unwrap(); + let rightmost_slash_idx = request_path.rfind('/').unwrap(); if rightmost_slash_idx == 0 { // There's only one slash; it's the first character return "/"; @@ -178,11 +178,11 @@ impl Cookie { ( // The cookie-path is a prefix of the request-path, and the last // character of the cookie-path is %x2F ("/"). - cookie_path.ends_with("/") || + cookie_path.ends_with('/') || // The cookie-path is a prefix of the request-path, and the first // character of the request-path that is not included in the cookie- // path is a %x2F ("/") character. - request_path[cookie_path.len()..].starts_with("/") + request_path[cookie_path.len()..].starts_with('/') )) } @@ -205,15 +205,13 @@ impl Cookie { if self.cookie.domain() != domain { return false; } - } else { - if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain()) { - if !Cookie::domain_match(domain, cookie_domain) { - return false; - } + } else if let (Some(domain), Some(cookie_domain)) = (domain, &self.cookie.domain()) { + if !Cookie::domain_match(domain, cookie_domain) { + return false; } } - if let Some(ref cookie_path) = self.cookie.path() { + if let Some(cookie_path) = self.cookie.path() { if !Cookie::path_match(url.path(), cookie_path) { return false; } diff --git a/components/net/cookie_storage.rs b/components/net/cookie_storage.rs index d6fef773589..75b604523cf 100644 --- a/components/net/cookie_storage.rs +++ b/components/net/cookie_storage.rs @@ -42,7 +42,7 @@ impl CookieStorage { source: CookieSource, ) -> Result, ()> { let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&"")); - let cookies = self.cookies_map.entry(domain).or_insert(vec![]); + let cookies = self.cookies_map.entry(domain).or_default(); // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2 if !cookie.cookie.secure().unwrap_or(false) && !url.is_secure_scheme() { @@ -90,7 +90,7 @@ impl CookieStorage { } pub fn clear_storage(&mut self, url: &ServoUrl) { let domain = reg_host(url.host_str().unwrap_or("")); - let cookies = self.cookies_map.entry(domain).or_insert(vec![]); + let cookies = self.cookies_map.entry(domain).or_default(); for cookie in cookies.iter_mut() { cookie.set_expiry_time_negative(); } @@ -116,12 +116,12 @@ impl CookieStorage { } // Step 12 - let domain = reg_host(&cookie.cookie.domain().as_ref().unwrap_or(&"")); - let cookies = self.cookies_map.entry(domain).or_insert(vec![]); + let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&"")); + let cookies = self.cookies_map.entry(domain).or_default(); if cookies.len() == self.max_per_host { let old_len = cookies.len(); - cookies.retain(|c| !is_cookie_expired(&c)); + cookies.retain(|c| !is_cookie_expired(c)); let new_len = cookies.len(); // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt @@ -153,8 +153,8 @@ impl CookieStorage { let domain = reg_host(url.host_str().unwrap_or("")); if let Entry::Occupied(mut entry) = self.cookies_map.entry(domain) { let cookies = entry.get_mut(); - cookies.retain(|c| !is_cookie_expired(&c)); - if cookies.len() == 0 { + cookies.retain(|c| !is_cookie_expired(c)); + if cookies.is_empty() { entry.remove_entry(); } } @@ -179,10 +179,10 @@ impl CookieStorage { }; // Step 2 let domain = reg_host(url.host_str().unwrap_or("")); - let cookies = self.cookies_map.entry(domain).or_insert(vec![]); + let cookies = self.cookies_map.entry(domain).or_default(); let mut url_cookies: Vec<&mut Cookie> = cookies.iter_mut().filter(filterer).collect(); - url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(*a, *b)); + url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(a, b)); let reducer = |acc: String, c: &mut &mut Cookie| -> String { // Step 3 @@ -192,9 +192,9 @@ impl CookieStorage { (match acc.len() { 0 => acc, _ => acc + "; ", - }) + &c.cookie.name() + + }) + c.cookie.name() + "=" + - &c.cookie.value() + c.cookie.value() }; let result = url_cookies.iter_mut().fold("".to_owned(), reducer); @@ -211,7 +211,7 @@ impl CookieStorage { source: CookieSource, ) -> impl Iterator> + 'a { let domain = reg_host(url.host_str().unwrap_or("")); - let cookies = self.cookies_map.entry(domain).or_insert(vec![]); + let cookies = self.cookies_map.entry(domain).or_default(); cookies .iter_mut() @@ -223,7 +223,7 @@ impl CookieStorage { } } -fn reg_host<'a>(url: &'a str) -> String { +fn reg_host(url: &str) -> String { reg_suffix(url).to_lowercase() } @@ -250,10 +250,10 @@ fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec) -> bool { cookies.remove(index); } } - return true; + true } -fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec) -> Option<(usize, Tm)> { +fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut [Cookie]) -> Option<(usize, Tm)> { let mut oldest_accessed: Option<(usize, Tm)> = None; for (i, c) in cookies.iter().enumerate() { if (c.cookie.secure().unwrap_or(false) == is_secure_cookie) && diff --git a/components/net/decoder.rs b/components/net/decoder.rs index 175ca401281..8f11d60eb0d 100644 --- a/components/net/decoder.rs +++ b/components/net/decoder.rs @@ -130,7 +130,7 @@ impl Decoder { Decoder { inner: Inner::Pending(Pending { body: ReadableChunks::new(body), - type_: type_, + type_, }), } } @@ -222,7 +222,7 @@ impl Gzip { Gzip { buf: BytesMut::with_capacity(INIT_BUFFER_SIZE), inner: Box::new(gzip::Decoder::new(Peeked::new(stream))), - reader: reader, + reader, } } } @@ -248,7 +248,7 @@ fn poll_with_read(reader: &mut dyn Read, buf: &mut BytesMut) -> Poll Poll::Ready(None), + Ok(0) => Poll::Ready(None), Ok(read) => { unsafe { buf.advance_mut(read) }; let chunk = buf.split_to(read).freeze(); @@ -286,7 +286,7 @@ impl Brotli { Self { buf: BytesMut::with_capacity(INIT_BUFFER_SIZE), inner: Box::new(Decompressor::new(Peeked::new(stream), BUF_SIZE)), - reader: reader, + reader, } } } @@ -318,7 +318,7 @@ impl Deflate { Self { buf: BytesMut::with_capacity(INIT_BUFFER_SIZE), inner: Box::new(DeflateDecoder::new(Peeked::new(stream))), - reader: reader, + reader, } } } @@ -382,7 +382,7 @@ impl Peeked { Peeked { state: PeekedState::NotReady, peeked_buf: [0; 10], - inner: inner, + inner, pos: 0, } } @@ -418,10 +418,10 @@ impl Read for Peeked { return Ok(len); }, PeekedState::NotReady => { - let mut buf = &mut self.peeked_buf[self.pos..]; + let buf = &mut self.peeked_buf[self.pos..]; let stream = self.inner.clone(); let mut reader = stream.lock().unwrap(); - let read = reader.read(&mut buf); + let read = reader.read(buf); match read { Ok(0) => self.ready(), @@ -444,7 +444,7 @@ impl ReadableChunks { fn new(stream: S) -> Self { ReadableChunks { state: ReadState::NotReady, - stream: stream, + stream, waker: None, } } diff --git a/components/net/fetch/cors_cache.rs b/components/net/fetch/cors_cache.rs index 666a160a591..f7798b79501 100644 --- a/components/net/fetch/cors_cache.rs +++ b/components/net/fetch/cors_cache.rs @@ -60,11 +60,11 @@ impl CorsCacheEntry { header_or_method: HeaderOrMethod, ) -> CorsCacheEntry { CorsCacheEntry { - origin: origin, - url: url, - max_age: max_age, - credentials: credentials, - header_or_method: header_or_method, + origin, + url, + max_age, + credentials, + header_or_method, created: time::now().to_timespec(), } } @@ -77,14 +77,10 @@ fn match_headers(cors_cache: &CorsCacheEntry, cors_req: &Request) -> bool { } /// A simple, vector-based CORS Cache -#[derive(Clone)] +#[derive(Clone, Default)] pub struct CorsCache(Vec); impl CorsCache { - pub fn new() -> CorsCache { - CorsCache(vec![]) - } - fn find_entry_by_header<'a>( &'a mut self, request: &Request, @@ -122,7 +118,7 @@ impl CorsCache { /// Returns true if an entry with a /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found pub fn match_header(&mut self, request: &Request, header_name: &HeaderName) -> bool { - self.find_entry_by_header(&request, header_name).is_some() + self.find_entry_by_header(request, header_name).is_some() } /// Updates max age if an entry for a @@ -136,7 +132,7 @@ impl CorsCache { new_max_age: u32, ) -> bool { match self - .find_entry_by_header(&request, header_name) + .find_entry_by_header(request, header_name) .map(|e| e.max_age = new_max_age) { Some(_) => true, @@ -156,7 +152,7 @@ impl CorsCache { /// Returns true if an entry with a /// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found pub fn match_method(&mut self, request: &Request, method: Method) -> bool { - self.find_entry_by_method(&request, method).is_some() + self.find_entry_by_method(request, method).is_some() } /// Updates max age if an entry for @@ -170,7 +166,7 @@ impl CorsCache { new_max_age: u32, ) -> bool { match self - .find_entry_by_method(&request, method.clone()) + .find_entry_by_method(request, method.clone()) .map(|e| e.max_age = new_max_age) { Some(_) => true, diff --git a/components/net/fetch/headers.rs b/components/net/fetch/headers.rs index 3a29f841d64..d306cda0057 100644 --- a/components/net/fetch/headers.rs +++ b/components/net/fetch/headers.rs @@ -17,14 +17,14 @@ pub fn determine_nosniff(headers: &HeaderMap) -> bool { match values { None => false, - Some(values) => !values.is_empty() && (&values[0]).eq_ignore_ascii_case("nosniff"), + Some(values) => !values.is_empty() && values[0].eq_ignore_ascii_case("nosniff"), } } /// fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option> { fn char_is_not_quote_or_comma(c: char) -> bool { - return c != '\u{0022}' && c != '\u{002C}'; + c != '\u{0022}' && c != '\u{002C}' } // Step 1 @@ -33,7 +33,7 @@ fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option(); + let input = input.into_iter().map(char::from).collect::(); // Step 2 let mut position = input.chars().peekable(); @@ -81,7 +81,7 @@ fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option @@ -102,13 +102,13 @@ where } // Step 3 - return result; + result } /// fn collect_http_quoted_string(position: &mut Peekable, extract_value: bool) -> String { fn char_is_not_quote_or_backslash(c: char) -> bool { - return c != '\u{0022}' && c != '\u{005C}'; + c != '\u{0022}' && c != '\u{005C}' } // Step 2 @@ -159,5 +159,5 @@ fn collect_http_quoted_string(position: &mut Peekable, extract_value: boo } // Step 6, 7 - return value; + value } diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index f98297b197b..42a95f542ea 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -84,7 +84,7 @@ pub struct CancellationListener { impl CancellationListener { pub fn new(cancel_chan: Option>) -> Self { Self { - cancel_chan: cancel_chan, + cancel_chan, cancelled: false, } } @@ -121,7 +121,7 @@ pub async fn fetch(request: &mut Request, target: Target<'_>, context: &FetchCon .unwrap() .set_attribute(ResourceAttribute::StartTime(ResourceTimeValue::FetchStart)); - fetch_with_cors_cache(request, &mut CorsCache::new(), target, context).await; + fetch_with_cors_cache(request, &mut CorsCache::default(), target, context).await; } pub async fn fetch_with_cors_cache( @@ -161,7 +161,7 @@ pub async fn fetch_with_cors_cache( } // Step 8. - main_fetch(request, cache, false, false, target, &mut None, &context).await; + main_fetch(request, cache, false, false, target, &mut None, context).await; } /// @@ -209,15 +209,15 @@ pub async fn main_fetch( } // Step 2. - if request.local_urls_only { - if !matches!( + if request.local_urls_only && + !matches!( request.current_url().scheme(), "about" | "blob" | "data" | "filesystem" - ) { - response = Some(Response::network_error(NetworkError::Internal( - "Non-local scheme".into(), - ))); - } + ) + { + response = Some(Response::network_error(NetworkError::Internal( + "Non-local scheme".into(), + ))); } // Step 2.2. @@ -267,7 +267,7 @@ pub async fn main_fetch( ) }, }; - request.referrer = referrer_url.map_or(Referrer::NoReferrer, |url| Referrer::ReferrerUrl(url)); + request.referrer = referrer_url.map_or(Referrer::NoReferrer, Referrer::ReferrerUrl); // Step 9. // TODO: handle FTP URLs. @@ -440,10 +440,7 @@ pub async fn main_fetch( let not_network_error = !response_is_network_error && !internal_response.is_network_error(); if not_network_error && (is_null_body_status(&internal_response.status) || - match request.method { - Method::HEAD | Method::CONNECT => true, - _ => false, - }) + matches!(request.method, Method::HEAD | Method::CONNECT)) { // when Fetch is used only asynchronously, we will need to make sure // that nothing tries to write to the body at this point @@ -451,7 +448,7 @@ pub async fn main_fetch( *body = ResponseBody::Empty; } - internal_response.get_network_error().map(|e| e.clone()) + internal_response.get_network_error().cloned() }; // Execute deferred rebinding of response. @@ -469,7 +466,7 @@ pub async fn main_fetch( response_loaded = true; // Step 19.2. - let ref integrity_metadata = &request.integrity_metadata; + let integrity_metadata = &request.integrity_metadata; if response.termination_reason.is_none() && !is_response_integrity_valid(integrity_metadata, &response) { @@ -487,7 +484,7 @@ pub async fn main_fetch( if request.synchronous { // process_response is not supposed to be used // by sync fetch, but we overload it here for simplicity - target.process_response(&mut response); + target.process_response(&response); if !response_loaded { wait_for_response(&mut response, target, done_chan).await; } @@ -502,8 +499,8 @@ pub async fn main_fetch( // in http_network_fetch. However, we can't yet follow the request // upload progress, so I'm keeping it here for now and pretending // the body got sent in one chunk - target.process_request_body(&request); - target.process_request_eof(&request); + target.process_request_body(request); + target.process_request_eof(request); } // Step 22. @@ -518,7 +515,7 @@ pub async fn main_fetch( target.process_response_eof(&response); if let Ok(http_cache) = context.state.http_cache.write() { - http_cache.update_awaiting_consumers(&request, &response); + http_cache.update_awaiting_consumers(request, &response); } // Steps 25-27. @@ -820,10 +817,10 @@ async fn scheme_fetch( let (id, origin) = match parse_blob_url(&url) { Ok((id, origin)) => (id, origin), - Err(()) => { - return Response::network_error(NetworkError::Internal( - "Invalid blob url".into(), - )); + Err(error) => { + return Response::network_error(NetworkError::Internal(format!( + "Invalid blob URL ({error})" + ))); }, }; @@ -872,16 +869,13 @@ async fn scheme_fetch( } fn is_null_body_status(status: &Option<(StatusCode, String)>) -> bool { - match *status { - Some((status, _)) => match status { - StatusCode::SWITCHING_PROTOCOLS | - StatusCode::NO_CONTENT | - StatusCode::RESET_CONTENT | - StatusCode::NOT_MODIFIED => true, - _ => false, - }, - _ => false, - } + matches!( + status, + Some((StatusCode::SWITCHING_PROTOCOLS, ..)) | + Some((StatusCode::NO_CONTENT, ..)) | + Some((StatusCode::RESET_CONTENT, ..)) | + Some((StatusCode::NOT_MODIFIED, ..)) + ) } /// diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 90af2f37c87..0c7bc3a1aa0 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -5,7 +5,6 @@ use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{BufRead, BufReader, Read, Seek, SeekFrom}; -use std::mem; use std::ops::Index; use std::path::{Path, PathBuf}; use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering}; @@ -103,13 +102,12 @@ impl FileManager { let store = self.store.clone(); self.thread_pool .upgrade() - .and_then(|pool| { + .map(|pool| { pool.spawn(move || { if let Err(e) = store.try_read_file(&sender, id, origin) { let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e))); } }); - Some(()) }) .unwrap_or_else(|| { warn!("FileManager tried to read a file after CoreResourceManager has exited."); @@ -127,6 +125,7 @@ impl FileManager { // Read a file for the Fetch implementation. // It gets the required headers synchronously and reads the actual content // in a separate thread. + #[allow(clippy::too_many_arguments)] pub fn fetch_file( &self, done_sender: &mut TokioSender, @@ -160,11 +159,10 @@ impl FileManager { let embedder = self.embedder_proxy.clone(); self.thread_pool .upgrade() - .and_then(|pool| { + .map(|pool| { pool.spawn(move || { store.select_file(filter, sender, origin, opt_test_path, embedder); }); - Some(()) }) .unwrap_or_else(|| { warn!( @@ -177,11 +175,10 @@ impl FileManager { let embedder = self.embedder_proxy.clone(); self.thread_pool .upgrade() - .and_then(|pool| { + .map(|pool| { pool.spawn(move || { store.select_files(filter, sender, origin, opt_test_paths, embedder); }); - Some(()) }) .unwrap_or_else(|| { warn!( @@ -221,7 +218,7 @@ impl FileManager { let done_sender = done_sender.clone(); self.thread_pool .upgrade() - .and_then(|pool| { + .map(|pool| { pool.spawn(move || { loop { if cancellation_listener.lock().unwrap().cancelled() { @@ -266,7 +263,7 @@ impl FileManager { if length == 0 { let mut body = res_body.lock().unwrap(); let completed_body = match *body { - ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]), + ResponseBody::Receiving(ref mut body) => std::mem::take(body), _ => vec![], }; *body = ResponseBody::Done(completed_body); @@ -276,13 +273,13 @@ impl FileManager { reader.consume(length); } }); - Some(()) }) .unwrap_or_else(|| { warn!("FileManager tried to fetch a file in chunks after CoreResourceManager has exited."); }); } + #[allow(clippy::too_many_arguments)] fn fetch_blob_buf( &self, done_sender: &mut TokioSender, @@ -373,7 +370,7 @@ impl FileManager { FileImpl::Sliced(parent_id, inner_rel_pos) => { // Next time we don't need to check validity since // we have already done that for requesting URL if necessary. - return self.fetch_blob_buf( + self.fetch_blob_buf( done_sender, cancellation_listener, &parent_id, @@ -383,7 +380,7 @@ impl FileManager { RelativePos::full_range().slice_inner(&inner_rel_pos), ), response, - ); + ) }, } } @@ -411,7 +408,7 @@ impl FileManagerStore { origin_in: &FileOrigin, ) -> Result { match self.entries.read().unwrap().get(id) { - Some(ref entry) => { + Some(entry) => { if *origin_in != *entry.origin { Err(BlobURLStoreError::InvalidOrigin) } else { @@ -441,7 +438,7 @@ impl FileManagerStore { let zero_refs = entry.refs.load(Ordering::Acquire) == 0; // Check if no other fetch has acquired a token for this file. - let no_outstanding_tokens = entry.outstanding_tokens.len() == 0; + let no_outstanding_tokens = entry.outstanding_tokens.is_empty(); // Check if there is still a blob URL outstanding. let valid = entry.is_valid_url.load(Ordering::Acquire); @@ -450,7 +447,7 @@ impl FileManagerStore { let do_remove = zero_refs && no_outstanding_tokens && !valid; if do_remove { - entries.remove(&file_id); + entries.remove(file_id); } } } @@ -461,7 +458,7 @@ impl FileManagerStore { let parent_id = match entries.get(file_id) { Some(entry) => { if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl { - Some(parent_id.clone()) + Some(*parent_id) } else { None } @@ -477,7 +474,7 @@ impl FileManagerStore { return FileTokenCheck::ShouldFail; } let token = Uuid::new_v4(); - entry.outstanding_tokens.insert(token.clone()); + entry.outstanding_tokens.insert(token); return FileTokenCheck::Required(token); } FileTokenCheck::ShouldFail @@ -585,7 +582,6 @@ impl FileManagerStore { }, None => { let _ = sender.send(Err(FileManagerThreadError::UserCancelled)); - return; }, } } @@ -631,7 +627,6 @@ impl FileManagerStore { }, None => { let _ = sender.send(Err(FileManagerThreadError::UserCancelled)); - return; }, } } @@ -672,7 +667,7 @@ impl FileManagerStore { id, FileStoreEntry { origin: origin.to_string(), - file_impl: file_impl, + file_impl, refs: AtomicUsize::new(1), // Invalid here since create_entry is called by file selection is_valid_url: AtomicBool::new(false), @@ -687,11 +682,11 @@ impl FileManagerStore { }; Ok(SelectedFile { - id: id, + id, filename: filename_path.to_path_buf(), modified: modified_epoch, size: file_size, - type_string: type_string, + type_string, }) } @@ -798,13 +793,13 @@ impl FileManagerStore { let is_valid = entry.is_valid_url.load(Ordering::Acquire); // Check if no fetch has acquired a token for this file. - let no_outstanding_tokens = entry.outstanding_tokens.len() == 0; + let no_outstanding_tokens = entry.outstanding_tokens.is_empty(); // Can we remove this file? let do_remove = !is_valid && no_outstanding_tokens; if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl { - (do_remove, Some(parent_id.clone())) + (do_remove, Some(*parent_id)) } else { (do_remove, None) } @@ -831,22 +826,20 @@ impl FileManagerStore { } fn promote_memory(&self, id: Uuid, blob_buf: BlobBuf, set_valid: bool, origin: FileOrigin) { - match Url::parse(&origin) { - // parse to check sanity - Ok(_) => { - self.insert( - id, - FileStoreEntry { - origin, - file_impl: FileImpl::Memory(blob_buf), - refs: AtomicUsize::new(1), - is_valid_url: AtomicBool::new(set_valid), - outstanding_tokens: Default::default(), - }, - ); - }, - Err(_) => {}, + // parse to check sanity + if Url::parse(&origin).is_err() { + return; } + self.insert( + id, + FileStoreEntry { + origin, + file_impl: FileImpl::Memory(blob_buf), + refs: AtomicUsize::new(1), + is_valid_url: AtomicBool::new(set_valid), + outstanding_tokens: Default::default(), + }, + ); } fn set_blob_url_validity( @@ -867,13 +860,13 @@ impl FileManagerStore { let zero_refs = entry.refs.load(Ordering::Acquire) == 0; // Check if no fetch has acquired a token for this file. - let no_outstanding_tokens = entry.outstanding_tokens.len() == 0; + let no_outstanding_tokens = entry.outstanding_tokens.is_empty(); // Can we remove this file? let do_remove = zero_refs && no_outstanding_tokens; if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl { - (do_remove, Some(parent_id.clone()), Ok(())) + (do_remove, Some(*parent_id), Ok(())) } else { (do_remove, None, Ok(())) } @@ -913,7 +906,7 @@ fn read_file_in_chunks( buf.truncate(n); let blob_buf = BlobBuf { filename: opt_filename, - type_string: type_string, + type_string, size: size as u64, bytes: buf, }; diff --git a/components/net/hosts.rs b/components/net/hosts.rs index 8261c91415c..6a59e04c76a 100644 --- a/components/net/hosts.rs +++ b/components/net/hosts.rs @@ -19,7 +19,7 @@ lazy_static! { fn create_host_table() -> Option> { let path = env::var_os("HOST_FILE")?; - let file = File::open(&path).ok()?; + let file = File::open(path).ok()?; let mut reader = BufReader::new(file); let mut lines = String::new(); diff --git a/components/net/hsts.rs b/components/net/hsts.rs index 2d521cac821..7e8dca6ca82 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -33,9 +33,9 @@ impl HstsEntry { None } else { Some(HstsEntry { - host: host, + host, include_subdomains: (subdomains == IncludeSubdomains::Included), - max_age: max_age, + max_age, timestamp: Some(time::get_time().sec as u64), }) } @@ -60,18 +60,12 @@ impl HstsEntry { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct HstsList { pub entries_map: HashMap>, } impl HstsList { - pub fn new() -> HstsList { - HstsList { - entries_map: HashMap::new(), - } - } - /// Create an `HstsList` from the bytes of a JSON preload file. pub fn from_preload(preload_content: &str) -> Option { #[derive(Deserialize)] @@ -81,14 +75,14 @@ impl HstsList { let hsts_entries: Option = serde_json::from_str(preload_content).ok(); - hsts_entries.map_or(None, |hsts_entries| { - let mut hsts_list: HstsList = HstsList::new(); + hsts_entries.map(|hsts_entries| { + let mut hsts_list: HstsList = HstsList::default(); for hsts_entry in hsts_entries.entries { hsts_list.push(hsts_entry); } - return Some(hsts_list); + hsts_list }) } @@ -112,7 +106,7 @@ impl HstsList { fn has_domain(&self, host: &str, base_domain: &str) -> bool { self.entries_map.get(base_domain).map_or(false, |entries| { - entries.iter().any(|e| e.matches_domain(&host)) + entries.iter().any(|e| e.matches_domain(host)) }) } @@ -128,10 +122,7 @@ impl HstsList { let have_domain = self.has_domain(&entry.host, base_domain); let have_subdomain = self.has_subdomain(&entry.host, base_domain); - let entries = self - .entries_map - .entry(base_domain.to_owned()) - .or_insert(vec![]); + let entries = self.entries_map.entry(base_domain.to_owned()).or_default(); if !have_domain && !have_subdomain { entries.push(entry); } else if !have_subdomain { diff --git a/components/net/http_cache.rs b/components/net/http_cache.rs index 11d83fe1644..17dffdea870 100644 --- a/components/net/http_cache.rs +++ b/components/net/http_cache.rs @@ -126,7 +126,7 @@ pub struct CachedResponse { } /// A memory cache. -#[derive(MallocSizeOf)] +#[derive(Default, MallocSizeOf)] pub struct HttpCache { /// cached responses. entries: HashMap>, @@ -134,10 +134,10 @@ pub struct HttpCache { /// Determine if a response is cacheable by default fn is_cacheable_by_default(status_code: u16) -> bool { - match status_code { - 200 | 203 | 204 | 206 | 300 | 301 | 404 | 405 | 410 | 414 | 501 => true, - _ => false, - } + matches!( + status_code, + 200 | 203 | 204 | 206 | 300 | 301 | 404 | 405 | 410 | 414 | 501 + ) } /// Determine if a given response is cacheable. @@ -192,19 +192,18 @@ fn calculate_response_age(response: &Response) -> Duration { /// or uses a heuristic if none are present. fn get_response_expiry(response: &Response) -> Duration { // Calculating Freshness Lifetime - let age = calculate_response_age(&response); + let age = calculate_response_age(response); if let Some(directives) = response.headers.typed_get::() { if directives.no_cache() { // Requires validation on first use. return Duration::seconds(0i64); - } else { - if let Some(secs) = directives.max_age().or(directives.s_max_age()) { - let max_age = Duration::from_std(secs).unwrap(); - if max_age < age { - return Duration::seconds(0i64); - } - return max_age - age; + } + if let Some(secs) = directives.max_age().or(directives.s_max_age()) { + let max_age = Duration::from_std(secs).unwrap(); + if max_age < age { + return Duration::seconds(0i64); } + return max_age - age; } } match response.headers.typed_get::() { @@ -217,9 +216,8 @@ fn get_response_expiry(response: &Response) -> Duration { if desired > current { return desired - current; - } else { - return Duration::seconds(0i64); } + return Duration::seconds(0i64); }, // Malformed Expires header, shouldn't be used to construct a valid response. None if response.headers.contains_key(header::EXPIRES) => return Duration::seconds(0i64), @@ -246,24 +244,23 @@ fn get_response_expiry(response: &Response) -> Duration { let last_modified = Timespec::new(last_modified.as_secs() as i64, 0); // A typical setting of this fraction might be 10%. let raw_heuristic_calc = (current - last_modified) / 10; - let result = if raw_heuristic_calc < max_heuristic { + + if raw_heuristic_calc < max_heuristic { raw_heuristic_calc } else { max_heuristic - }; - result + } } else { max_heuristic }; if is_cacheable_by_default(*code) { // Status codes that are cacheable by default can use heuristics to determine freshness. return heuristic_freshness; - } else { - // Other status codes can only use heuristic freshness if the public cache directive is present. - if let Some(ref directives) = response.headers.typed_get::() { - if directives.public() { - return heuristic_freshness; - } + } + // Other status codes can only use heuristic freshness if the public cache directive is present. + if let Some(ref directives) = response.headers.typed_get::() { + if directives.public() { + return heuristic_freshness; } } } @@ -335,9 +332,9 @@ fn create_cached_response( response.status = cached_resource.data.status.clone(); response.raw_status = cached_resource.data.raw_status.clone(); response.url_list = cached_resource.data.url_list.clone(); - response.https_state = cached_resource.data.https_state.clone(); + response.https_state = cached_resource.data.https_state; response.referrer = request.referrer.to_url().cloned(); - response.referrer_policy = request.referrer_policy.clone(); + response.referrer_policy = request.referrer_policy; response.aborted = cached_resource.aborted.clone(); let expires = cached_resource.data.expires; let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires); @@ -347,10 +344,9 @@ fn create_cached_response( // TODO: take must-revalidate into account // TODO: if this cache is to be considered shared, take proxy-revalidate into account // - let has_expired = - (adjusted_expires < time_since_validated) || (adjusted_expires == time_since_validated); + let has_expired = adjusted_expires <= time_since_validated; let cached_response = CachedResponse { - response: response, + response, needs_validation: has_expired, }; Some(cached_response) @@ -370,12 +366,12 @@ fn create_resource_with_bytes_from_resource( data: Measurable(MeasurableCachedResource { metadata: resource.data.metadata.clone(), location_url: resource.data.location_url.clone(), - https_state: resource.data.https_state.clone(), + https_state: resource.data.https_state, status: Some((StatusCode::PARTIAL_CONTENT, "Partial Content".into())), raw_status: Some((206, b"Partial Content".to_vec())), url_list: resource.data.url_list.clone(), - expires: resource.data.expires.clone(), - last_validated: resource.data.last_validated.clone(), + expires: resource.data.expires, + last_validated: resource.data.last_validated, }), } } @@ -413,7 +409,7 @@ fn handle_range_request( // see . // TODO: add support for complete and partial resources, // whose body is in the ResponseBody::Receiving state. - (&(Bound::Included(beginning), Bound::Included(end)), Some(ref complete_resource)) => { + (&(Bound::Included(beginning), Bound::Included(end)), Some(complete_resource)) => { if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() { if end == u64::max_value() { // Prevent overflow on the addition below. @@ -427,7 +423,7 @@ fn handle_range_request( create_resource_with_bytes_from_resource(bytes, complete_resource); let cached_headers = new_resource.data.metadata.headers.lock().unwrap(); let cached_response = - create_cached_response(request, &new_resource, &*cached_headers, done_chan); + create_cached_response(request, &new_resource, &cached_headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -451,7 +447,7 @@ fn handle_range_request( if res_beginning <= beginning && res_end >= end { let resource_body = &*partial_resource.body.lock().unwrap(); let requested = match resource_body { - &ResponseBody::Done(ref body) => { + ResponseBody::Done(body) => { let b = beginning as usize - res_beginning as usize; let e = end as usize - res_beginning as usize + 1; body.get(b..e) @@ -460,9 +456,9 @@ fn handle_range_request( }; if let Some(bytes) = requested { let new_resource = - create_resource_with_bytes_from_resource(&bytes, partial_resource); + create_resource_with_bytes_from_resource(bytes, partial_resource); let cached_response = - create_cached_response(request, &new_resource, &*headers, done_chan); + create_cached_response(request, &new_resource, &headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -470,7 +466,7 @@ fn handle_range_request( } } }, - (&(Bound::Included(beginning), Bound::Unbounded), Some(ref complete_resource)) => { + (&(Bound::Included(beginning), Bound::Unbounded), Some(complete_resource)) => { if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() { let b = beginning as usize; let requested = body.get(b..); @@ -479,7 +475,7 @@ fn handle_range_request( create_resource_with_bytes_from_resource(bytes, complete_resource); let cached_headers = new_resource.data.metadata.headers.lock().unwrap(); let cached_response = - create_cached_response(request, &new_resource, &*cached_headers, done_chan); + create_cached_response(request, &new_resource, &cached_headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -505,7 +501,7 @@ fn handle_range_request( if res_beginning < beginning && res_end == total - 1 { let resource_body = &*partial_resource.body.lock().unwrap(); let requested = match resource_body { - &ResponseBody::Done(ref body) => { + ResponseBody::Done(body) => { let from_byte = beginning as usize - res_beginning as usize; body.get(from_byte..) }, @@ -513,9 +509,9 @@ fn handle_range_request( }; if let Some(bytes) = requested { let new_resource = - create_resource_with_bytes_from_resource(&bytes, partial_resource); + create_resource_with_bytes_from_resource(bytes, partial_resource); let cached_response = - create_cached_response(request, &new_resource, &*headers, done_chan); + create_cached_response(request, &new_resource, &headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -523,7 +519,7 @@ fn handle_range_request( } } }, - (&(Bound::Unbounded, Bound::Included(offset)), Some(ref complete_resource)) => { + (&(Bound::Unbounded, Bound::Included(offset)), Some(complete_resource)) => { if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() { let from_byte = body.len() - offset as usize; let requested = body.get(from_byte..); @@ -532,7 +528,7 @@ fn handle_range_request( create_resource_with_bytes_from_resource(bytes, complete_resource); let cached_headers = new_resource.data.metadata.headers.lock().unwrap(); let cached_response = - create_cached_response(request, &new_resource, &*cached_headers, done_chan); + create_cached_response(request, &new_resource, &cached_headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -551,8 +547,8 @@ fn handle_range_request( } else { continue; }; - if !(total >= res_beginning) || - !(total >= res_end) || + if total < res_beginning || + total < res_end || offset == 0 || offset == u64::max_value() { @@ -562,7 +558,7 @@ fn handle_range_request( if (total - res_beginning) > (offset - 1) && (total - res_end) < offset + 1 { let resource_body = &*partial_resource.body.lock().unwrap(); let requested = match resource_body { - &ResponseBody::Done(ref body) => { + ResponseBody::Done(body) => { let from_byte = body.len() - offset as usize; body.get(from_byte..) }, @@ -570,9 +566,9 @@ fn handle_range_request( }; if let Some(bytes) = requested { let new_resource = - create_resource_with_bytes_from_resource(&bytes, partial_resource); + create_resource_with_bytes_from_resource(bytes, partial_resource); let cached_response = - create_cached_response(request, &new_resource, &*headers, done_chan); + create_cached_response(request, &new_resource, &headers, done_chan); if let Some(cached_response) = cached_response { return Some(cached_response); } @@ -587,13 +583,6 @@ fn handle_range_request( } impl HttpCache { - /// Create a new memory cache instance. - pub fn new() -> HttpCache { - HttpCache { - entries: HashMap::new(), - } - } - /// Constructing Responses from Caches. /// pub fn construct_response( @@ -608,11 +597,11 @@ impl HttpCache { debug!("non-GET method, not caching"); return None; } - let entry_key = CacheKey::new(&request); + let entry_key = CacheKey::new(request); let resources = self .entries .get(&entry_key)? - .into_iter() + .iter() .filter(|r| !r.aborted.load(Ordering::Relaxed)); let mut candidates = vec![]; for cached_resource in resources { @@ -671,36 +660,35 @@ impl HttpCache { range_spec.iter().collect(), done_chan, ); - } else { - while let Some(cached_resource) = candidates.pop() { - // Not a Range request. - // Do not allow 206 responses to be constructed. - // - // See https://tools.ietf.org/html/rfc7234#section-3.1 - // - // A cache MUST NOT use an incomplete response to answer requests unless the - // response has been made complete or the request is partial and - // specifies a range that is wholly within the incomplete response. - // - // TODO: Combining partial content to fulfill a non-Range request - // see https://tools.ietf.org/html/rfc7234#section-3.3 - match cached_resource.data.raw_status { - Some((ref code, _)) => { - if *code == 206 { - continue; - } - }, - None => continue, - } - // Returning a response that can be constructed - // TODO: select the most appropriate one, using a known mechanism from a selecting header field, - // or using the Date header to return the most recent one. - let cached_headers = cached_resource.data.metadata.headers.lock().unwrap(); - let cached_response = - create_cached_response(request, cached_resource, &*cached_headers, done_chan); - if let Some(cached_response) = cached_response { - return Some(cached_response); - } + } + while let Some(cached_resource) = candidates.pop() { + // Not a Range request. + // Do not allow 206 responses to be constructed. + // + // See https://tools.ietf.org/html/rfc7234#section-3.1 + // + // A cache MUST NOT use an incomplete response to answer requests unless the + // response has been made complete or the request is partial and + // specifies a range that is wholly within the incomplete response. + // + // TODO: Combining partial content to fulfill a non-Range request + // see https://tools.ietf.org/html/rfc7234#section-3.3 + match cached_resource.data.raw_status { + Some((ref code, _)) => { + if *code == 206 { + continue; + } + }, + None => continue, + } + // Returning a response that can be constructed + // TODO: select the most appropriate one, using a known mechanism from a selecting header field, + // or using the Date header to return the most recent one. + let cached_headers = cached_resource.data.metadata.headers.lock().unwrap(); + let cached_response = + create_cached_response(request, cached_resource, &cached_headers, done_chan); + if let Some(cached_response) = cached_response { + return Some(cached_response); } } debug!("couldn't find an appropriate response, not caching"); @@ -712,7 +700,7 @@ impl HttpCache { /// whose response body was still receiving data when the resource was constructed, /// and whose response has now either been completed or cancelled. pub fn update_awaiting_consumers(&self, request: &Request, response: &Response) { - let entry_key = CacheKey::new(&request); + let entry_key = CacheKey::new(request); let cached_resources = match self.entries.get(&entry_key) { None => return, @@ -762,9 +750,9 @@ impl HttpCache { done_chan: &mut DoneChannel, ) -> Option { assert_eq!(response.status.map(|s| s.0), Some(StatusCode::NOT_MODIFIED)); - let entry_key = CacheKey::new(&request); + let entry_key = CacheKey::new(request); if let Some(cached_resources) = self.entries.get_mut(&entry_key) { - for cached_resource in cached_resources.iter_mut() { + if let Some(cached_resource) = cached_resources.iter_mut().next() { // done_chan will have been set to Some(..) by http_network_fetch. // If the body is not receiving data, set the done_chan back to None. // Otherwise, create a new dedicated channel to update the consumer. @@ -794,9 +782,9 @@ impl HttpCache { ); constructed_response.body = cached_resource.body.clone(); constructed_response.status = cached_resource.data.status.clone(); - constructed_response.https_state = cached_resource.data.https_state.clone(); + constructed_response.https_state = cached_resource.data.https_state; constructed_response.referrer = request.referrer.to_url().cloned(); - constructed_response.referrer_policy = request.referrer_policy.clone(); + constructed_response.referrer_policy = request.referrer_policy; constructed_response.raw_status = cached_resource.data.raw_status.clone(); constructed_response.url_list = cached_resource.data.url_list.clone(); cached_resource.data.expires = get_response_expiry(&constructed_response); @@ -831,12 +819,12 @@ impl HttpCache { self.invalidate_for_url(&url); } } - if let Some(Ok(ref content_location)) = response + if let Some(Ok(content_location)) = response .headers .get(header::CONTENT_LOCATION) .map(HeaderValue::to_str) { - if let Ok(url) = request.current_url().join(&content_location) { + if let Ok(url) = request.current_url().join(content_location) { self.invalidate_for_url(&url); } } @@ -862,7 +850,7 @@ impl HttpCache { // responses to be stored is present in the response. return; }; - let entry_key = CacheKey::new(&request); + let entry_key = CacheKey::new(request); let metadata = match response.metadata() { Ok(FetchMetadata::Filtered { filtered: _, @@ -874,7 +862,7 @@ impl HttpCache { if !response_is_cacheable(&metadata) { return; } - let expiry = get_response_expiry(&response); + let expiry = get_response_expiry(response); let cacheable_metadata = CachedMetadata { headers: Arc::new(Mutex::new(response.headers.clone())), data: Measurable(MeasurableCachedMetadata { @@ -892,7 +880,7 @@ impl HttpCache { data: Measurable(MeasurableCachedResource { metadata: cacheable_metadata, location_url: response.location_url.clone(), - https_state: response.https_state.clone(), + https_state: response.https_state, status: response.status.clone(), raw_status: response.raw_status.clone(), url_list: response.url_list.clone(), @@ -900,7 +888,7 @@ impl HttpCache { last_validated: time::now(), }), }; - let entry = self.entries.entry(entry_key).or_insert_with(|| vec![]); + let entry = self.entries.entry(entry_key).or_default(); entry.push(entry_resource); // TODO: Complete incomplete responses, including 206 response, when stored here. // See A cache MAY complete a stored incomplete response by making a subsequent range request diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index bb75ebc5653..7f25e3a561f 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -5,8 +5,6 @@ use core::convert::Infallible; use std::collections::{HashMap, HashSet}; use std::iter::FromIterator; -use std::mem; -use std::ops::Deref; use std::sync::{Arc as StdArc, Condvar, Mutex, RwLock}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -21,8 +19,8 @@ use headers::authorization::Basic; use headers::{ AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlAllowOrigin, AccessControlMaxAge, AccessControlRequestHeaders, - AccessControlRequestMethod, Authorization, CacheControl, ContentEncoding, ContentLength, - HeaderMapExt, IfModifiedSince, LastModified, Origin as HyperOrigin, Pragma, Referer, UserAgent, + AccessControlRequestMethod, Authorization, CacheControl, ContentLength, HeaderMapExt, + IfModifiedSince, LastModified, Origin as HyperOrigin, Pragma, Referer, UserAgent, }; use http::header::{ self, HeaderValue, ACCEPT, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LOCATION, CONTENT_TYPE, @@ -87,6 +85,8 @@ pub enum HttpCacheEntryState { PendingStore(usize), } +type HttpCacheState = Mutex, Condvar)>>>; + pub struct HttpState { pub hsts_list: RwLock, pub cookie_jar: RwLock, @@ -94,22 +94,22 @@ pub struct HttpState { /// A map of cache key to entry state, /// reflecting whether the cache entry is ready to read from, /// or whether a concurrent pending store should be awaited. - pub http_cache_state: Mutex, Condvar)>>>, + pub http_cache_state: HttpCacheState, pub auth_cache: RwLock, pub history_states: RwLock>>, pub client: Client, pub override_manager: CertificateErrorOverrideManager, } -impl HttpState { - pub fn new() -> HttpState { +impl Default for HttpState { + fn default() -> Self { let override_manager = CertificateErrorOverrideManager::new(); - HttpState { - hsts_list: RwLock::new(HstsList::new()), + Self { + hsts_list: RwLock::new(HstsList::default()), cookie_jar: RwLock::new(CookieStorage::new(150)), - auth_cache: RwLock::new(AuthCache::new()), + auth_cache: RwLock::new(AuthCache::default()), history_states: RwLock::new(HashMap::new()), - http_cache: RwLock::new(HttpCache::new()), + http_cache: RwLock::new(HttpCache::default()), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client(create_tls_config( CACertificates::Default, @@ -193,7 +193,7 @@ fn no_referrer_when_downgrade(referrer_url: ServoUrl, current_url: ServoUrl) -> return None; } // Step 2 - return strip_url_for_use_as_referrer(referrer_url, false); + strip_url_for_use_as_referrer(referrer_url, false) } /// @@ -237,8 +237,8 @@ fn is_schemelessy_same_site(site_a: &ImmutableOrigin, site_b: &ImmutableOrigin) let host_b_reg = reg_suffix(&host_b); // Step 2.2-2.3 - (site_a.host() == site_b.host() && host_a_reg == "") || - (host_a_reg == host_b_reg && host_a_reg != "") + (site_a.host() == site_b.host() && host_a_reg.is_empty()) || + (host_a_reg == host_b_reg && !host_a_reg.is_empty()) } else { // Step 3 false @@ -345,11 +345,12 @@ fn set_cookies_from_headers( ) { for cookie in headers.get_all(header::SET_COOKIE) { if let Ok(cookie_str) = std::str::from_utf8(cookie.as_bytes()) { - set_cookie_for_url(&cookie_jar, &url, &cookie_str); + set_cookie_for_url(cookie_jar, url, cookie_str); } } } +#[allow(clippy::too_many_arguments)] fn prepare_devtools_request( request_id: String, url: ServoUrl, @@ -363,16 +364,16 @@ fn prepare_devtools_request( is_xhr: bool, ) -> ChromeToDevtoolsControlMsg { let request = DevtoolsHttpRequest { - url: url, - method: method, - headers: headers, - body: body, - pipeline_id: pipeline_id, + url, + method, + headers, + body, + pipeline_id, startedDateTime: now, timeStamp: now.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as i64, - connect_time: connect_time, - send_time: send_time, - is_xhr: is_xhr, + connect_time, + send_time, + is_xhr, }; let net_event = NetworkEvent::HttpRequest(request); @@ -396,10 +397,10 @@ fn send_response_to_devtools( pipeline_id: PipelineId, ) { let response = DevtoolsHttpResponse { - headers: headers, - status: status, + headers, + status, body: None, - pipeline_id: pipeline_id, + pipeline_id, }; let net_event_response = NetworkEvent::HttpResponse(response); @@ -411,7 +412,7 @@ fn auth_from_cache( auth_cache: &RwLock, origin: &ImmutableOrigin, ) -> Option> { - if let Some(ref auth_entry) = auth_cache + if let Some(auth_entry) = auth_cache .read() .unwrap() .entries @@ -480,6 +481,7 @@ impl BodySink { } } +#[allow(clippy::too_many_arguments)] async fn obtain_response( client: &Client, url: &ServoUrl, @@ -503,9 +505,9 @@ async fn obtain_response( .clone() .into_url() .as_ref() - .replace("|", "%7C") - .replace("{", "%7B") - .replace("}", "%7D"); + .replace('|', "%7C") + .replace('{', "%7B") + .replace('}', "%7D"); let request = if let Some(chunk_requester) = body { let (sink, stream) = if source_is_null { @@ -649,7 +651,7 @@ async fn obtain_response( .set_attribute(ResourceAttribute::ConnectEnd(connect_end)); let request_id = request_id.map(|v| v.to_owned()); - let pipeline_id = pipeline_id.clone(); + let pipeline_id = *pipeline_id; let closure_url = url.clone(); let method = method.clone(); let send_start = precise_time_ms(); @@ -705,6 +707,7 @@ async fn obtain_response( /// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch) #[async_recursion] +#[allow(clippy::too_many_arguments)] pub async fn http_fetch( request: &mut Request, cache: &mut CorsCache, @@ -760,13 +763,13 @@ pub async fn http_fetch( let method_mismatch = !method_cache_match && (!is_cors_safelisted_method(&request.method) || request.use_cors_preflight); let header_mismatch = request.headers.iter().any(|(name, value)| { - !cache.match_header(&*request, &name) && + !cache.match_header(&*request, name) && !is_cors_safelisted_request_header(&name, &value) }); // Sub-substep 1 if method_mismatch || header_mismatch { - let preflight_result = cors_preflight_fetch(&request, cache, context).await; + let preflight_result = cors_preflight_fetch(request, cache, context).await; // Sub-substep 2 if let Some(e) = preflight_result.get_network_error() { return Response::network_error(e.clone()); @@ -798,7 +801,7 @@ pub async fn http_fetch( .await; // Substep 4 - if cors_flag && cors_check(&request, &fetch_result).is_err() { + if cors_flag && cors_check(request, &fetch_result).is_err() { return Response::network_error(NetworkError::Internal("CORS check failed".into())); } @@ -834,7 +837,7 @@ pub async fn http_fetch( .and_then(|v| { HeaderValue::to_str(v) .map(|l| { - ServoUrl::parse_with_base(response.actual_response().url(), &l) + ServoUrl::parse_with_base(response.actual_response().url(), l) .map_err(|err| err.to_string()) }) .ok() @@ -1093,7 +1096,7 @@ fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option< ("http", 80) | ("https", 443) => None, _ => Some(*port), }; - HyperOrigin::try_from_parts(&scheme, &host.to_string(), port).ok() + HyperOrigin::try_from_parts(scheme, &host.to_string(), port).ok() }, } } @@ -1257,13 +1260,14 @@ async fn http_network_or_cache_fetch( } // Substep 5 - if authentication_fetch_flag && authorization_value.is_none() { - if has_credentials(¤t_url) { - authorization_value = Some(Authorization::basic( - current_url.username(), - current_url.password().unwrap_or(""), - )); - } + if authentication_fetch_flag && + authorization_value.is_none() && + has_credentials(¤t_url) + { + authorization_value = Some(Authorization::basic( + current_url.username(), + current_url.password().unwrap_or(""), + )); } // Substep 6 @@ -1285,7 +1289,7 @@ async fn http_network_or_cache_fetch( // That one happens when a fetch gets a cache hit, and the resource is pending completion from the network. { let (lock, cvar) = { - let entry_key = CacheKey::new(&http_request); + let entry_key = CacheKey::new(http_request); let mut state_map = context.state.http_cache_state.lock().unwrap(); &*state_map .entry(entry_key) @@ -1314,7 +1318,7 @@ async fn http_network_or_cache_fetch( // Step 5.19 if let Ok(http_cache) = context.state.http_cache.read() { if let Some(response_from_cache) = - http_cache.construct_response(&http_request, done_chan) + http_cache.construct_response(http_request, done_chan) { let response_headers = response_from_cache.response.headers.clone(); // Substep 1, 2, 3, 4 @@ -1378,7 +1382,7 @@ async fn http_network_or_cache_fetch( // if no stores are pending. fn update_http_cache_state(context: &FetchContext, http_request: &Request) { let (lock, cvar) = { - let entry_key = CacheKey::new(&http_request); + let entry_key = CacheKey::new(http_request); let mut state_map = context.state.http_cache_state.lock().unwrap(); &*state_map .get_mut(&entry_key) @@ -1437,7 +1441,7 @@ async fn http_network_or_cache_fetch( if http_request.cache_mode == CacheMode::OnlyIfCached { // The cache will not be updated, // set its state to ready to construct. - update_http_cache_state(context, &http_request); + update_http_cache_state(context, http_request); return Response::network_error(NetworkError::Internal( "Couldn't find response in cache".into(), )); @@ -1452,7 +1456,7 @@ async fn http_network_or_cache_fetch( if let Some((200..=399, _)) = forward_response.raw_status { if !http_request.method.is_safe() { if let Ok(mut http_cache) = context.state.http_cache.write() { - http_cache.invalidate(&http_request, &forward_response); + http_cache.invalidate(http_request, &forward_response); } } } @@ -1467,7 +1471,7 @@ async fn http_network_or_cache_fetch( // Ensure done_chan is None, // since the network response will be replaced by the revalidated stored one. *done_chan = None; - response = http_cache.refresh(&http_request, forward_response.clone(), done_chan); + response = http_cache.refresh(http_request, forward_response.clone(), done_chan); } wait_for_cached_response(done_chan, &mut response).await; } @@ -1477,7 +1481,7 @@ async fn http_network_or_cache_fetch( if http_request.cache_mode != CacheMode::NoStore { // Subsubstep 2, doing it first to avoid a clone of forward_response. if let Ok(mut http_cache) = context.state.http_cache.write() { - http_cache.store(&http_request, &forward_response); + http_cache.store(http_request, &forward_response); } } // Subsubstep 1 @@ -1488,7 +1492,7 @@ async fn http_network_or_cache_fetch( let mut response = response.unwrap(); // The cache has been updated, set its state to ready to construct. - update_http_cache_state(context, &http_request); + update_http_cache_state(context, http_request); // Step 8 // TODO: if necessary set response's range-requested flag @@ -1537,7 +1541,7 @@ async fn http_network_or_cache_fetch( // Step 5 if let Origin::Origin(ref request_origin) = request.origin { let schemeless_same_origin = - is_schemelessy_same_site(&request_origin, ¤t_url_origin); + is_schemelessy_same_site(request_origin, ¤t_url_origin); if schemeless_same_origin && (request_origin.scheme() == Some("https") || response.https_state == HttpsState::None) @@ -1555,7 +1559,7 @@ async fn http_network_or_cache_fetch( } if http_request.response_tainting != ResponseTainting::CorsTainting && - cross_origin_resource_policy_check(&http_request, &response) == + cross_origin_resource_policy_check(http_request, &response) == CrossOriginResourcePolicy::Blocked { return Response::network_error(NetworkError::Internal( @@ -1722,7 +1726,7 @@ async fn http_network_fetch( .map(|body| body.source_is_null()) .unwrap_or(false), &request.pipeline_id, - request_id.as_ref().map(Deref::deref), + request_id.as_deref(), is_xhr, context, fetch_terminated_sender, @@ -1796,7 +1800,7 @@ async fn http_network_fetch( )); response.headers = res.headers().clone(); response.referrer = request.referrer.to_url().cloned(); - response.referrer_policy = request.referrer_policy.clone(); + response.referrer_policy = request.referrer_policy; let res_body = response.body.clone(); @@ -1834,7 +1838,7 @@ async fn http_network_fetch( send_response_to_devtools( &sender, request_id.unwrap(), - meta_headers.map(|hdrs| Serde::into_inner(hdrs)), + meta_headers.map(Serde::into_inner), meta_status, pipeline_id, ); @@ -1852,7 +1856,6 @@ async fn http_network_fetch( res.into_body() .map_err(|e| { warn!("Error streaming response body: {:?}", e); - () }) .try_fold(res_body, move |res_body, chunk| { if cancellation_listener.lock().unwrap().cancelled() { @@ -1862,7 +1865,7 @@ async fn http_network_fetch( } if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() { let bytes = chunk; - body.extend_from_slice(&*bytes); + body.extend_from_slice(&bytes); let _ = done_sender.send(Data::Payload(bytes.to_vec())); } future::ready(Ok(res_body)) @@ -1871,7 +1874,7 @@ async fn http_network_fetch( debug!("successfully finished response for {:?}", url1); let mut body = res_body.lock().unwrap(); let completed_body = match *body { - ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]), + ResponseBody::Receiving(ref mut body) => std::mem::take(body), _ => vec![], }; *body = ResponseBody::Done(completed_body); @@ -1886,7 +1889,7 @@ async fn http_network_fetch( debug!("finished response for {:?}", url2); let mut body = res_body2.lock().unwrap(); let completed_body = match *body { - ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]), + ResponseBody::Receiving(ref mut body) => std::mem::take(body), _ => vec![], }; *body = ResponseBody::Done(completed_body); @@ -1913,16 +1916,6 @@ async fn http_network_fetch( // Step 6-11 // (needs stream bodies) - // Step 12 - // TODO when https://bugzilla.mozilla.org/show_bug.cgi?id=1030660 - // is resolved, this step will become uneccesary - // TODO this step - if let Some(encoding) = response.headers.typed_get::() { - if encoding.contains("gzip") { - } else if encoding.contains("compress") { - } - }; - // Step 13 // TODO this step isn't possible yet (CSP) @@ -1974,8 +1967,8 @@ async fn cors_preflight_fetch( Origin::Origin(origin) => origin.clone(), }) .pipeline_id(request.pipeline_id) - .initiator(request.initiator.clone()) - .destination(request.destination.clone()) + .initiator(request.initiator) + .destination(request.destination) .referrer_policy(request.referrer_policy) .mode(RequestMode::CorsMode) .response_tainting(ResponseTainting::CorsTainting) @@ -2007,7 +2000,7 @@ async fn cors_preflight_fetch( let response = http_network_or_cache_fetch(&mut preflight, false, false, &mut None, context).await; // Step 7 - if cors_check(&request, &response).is_ok() && + if cors_check(request, &response).is_ok() && response .status .as_ref() @@ -2079,7 +2072,7 @@ async fn cors_preflight_fetch( // Substep 6 if request.headers.iter().any(|(name, _)| { - is_cors_non_wildcard_request_header_name(&name) && + is_cors_non_wildcard_request_header_name(name) && header_names.iter().all(|hn| hn != name) }) { return Response::network_error(NetworkError::Internal( @@ -2089,6 +2082,7 @@ async fn cors_preflight_fetch( // Substep 7 let unsafe_names = get_cors_unsafe_header_names(&request.headers); + #[allow(clippy::mutable_key_type)] // We don't mutate the items in the set let header_names_set: HashSet<&HeaderName> = HashSet::from_iter(header_names.iter()); let header_names_contains_star = header_names.iter().any(|hn| hn.as_str() == "*"); for unsafe_name in unsafe_names.iter() { @@ -2116,12 +2110,12 @@ async fn cors_preflight_fetch( // Substep 12, 13 for method in &methods { - cache.match_method_and_update(&*request, method.clone(), max_age); + cache.match_method_and_update(request, method.clone(), max_age); } // Substep 14, 15 for header_name in &header_names { - cache.match_header_and_update(&*request, &*header_name, max_age); + cache.match_header_and_update(request, header_name, max_age); } // Substep 16 @@ -2192,12 +2186,12 @@ fn is_no_store_cache(headers: &HeaderMap) -> bool { /// pub fn is_redirect_status(status: &(StatusCode, String)) -> bool { - match status.0 { + matches!( + status.0, StatusCode::MOVED_PERMANENTLY | - StatusCode::FOUND | - StatusCode::SEE_OTHER | - StatusCode::TEMPORARY_REDIRECT | - StatusCode::PERMANENT_REDIRECT => true, - _ => false, - } + StatusCode::FOUND | + StatusCode::SEE_OTHER | + StatusCode::TEMPORARY_REDIRECT | + StatusCode::PERMANENT_REDIRECT + ) } diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs index 5f30884ecf1..9235c8d251e 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -4,8 +4,9 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::HashMap; -use std::mem; +use std::num::NonZeroUsize; use std::sync::{Arc, Mutex}; +use std::{mem, thread}; use embedder_traits::resources::{self, Resource}; use imsz::imsz_from_reader; @@ -43,14 +44,11 @@ use crate::resource_thread::CoreResourceThreadPool; fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg { let image = load_from_memory(bytes, cors); - DecoderMsg { - key: key, - image: image, - } + DecoderMsg { key, image } } fn get_placeholder_image(webrender_api: &WebrenderIpcSender, data: &[u8]) -> Arc { - let mut image = load_from_memory(&data, CorsStatus::Unsafe).unwrap(); + let mut image = load_from_memory(data, CorsStatus::Unsafe).unwrap(); set_webrender_image_key(webrender_api, &mut image); Arc::new(image) } @@ -62,7 +60,7 @@ fn set_webrender_image_key(webrender_api: &WebrenderIpcSender, image: &mut Image let mut bytes = Vec::new(); let is_opaque = match image.format { PixelFormat::BGRA8 => { - bytes.extend_from_slice(&*image.bytes); + bytes.extend_from_slice(&image.bytes); pixels::rgba8_premultiply_inplace(bytes.as_mut_slice()) }, PixelFormat::RGB8 => { @@ -129,7 +127,7 @@ impl AllPendingLoads { } fn remove(&mut self, key: &LoadKey) -> Option { - self.loads.remove(key).and_then(|pending_load| { + self.loads.remove(key).map(|pending_load| { self.url_to_load_key .remove(&( pending_load.url.clone(), @@ -137,16 +135,16 @@ impl AllPendingLoads { pending_load.cors_setting, )) .unwrap(); - Some(pending_load) + pending_load }) } - fn get_cached<'a>( - &'a mut self, + fn get_cached( + &mut self, url: ServoUrl, origin: ImmutableOrigin, cors_status: Option, - ) -> CacheResult<'a> { + ) -> CacheResult<'_> { match self .url_to_load_key .entry((url.clone(), origin.clone(), cors_status)) @@ -191,10 +189,7 @@ struct CompletedLoad { impl CompletedLoad { fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad { - CompletedLoad { - image_response: image_response, - id: id, - } + CompletedLoad { image_response, id } } } @@ -223,7 +218,7 @@ impl ImageBytes { ImageBytes::InProgress(ref mut bytes) => bytes, ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"), }; - mem::replace(own_bytes, vec![]) + mem::take(own_bytes) }; let bytes = Arc::new(bytes); *self = ImageBytes::Complete(bytes.clone()); @@ -232,8 +227,8 @@ impl ImageBytes { fn as_slice(&self) -> &[u8] { match *self { - ImageBytes::InProgress(ref bytes) => &bytes, - ImageBytes::Complete(ref bytes) => &*bytes, + ImageBytes::InProgress(ref bytes) => bytes, + ImageBytes::Complete(ref bytes) => bytes, } } } @@ -306,7 +301,7 @@ impl PendingLoad { metadata: None, result: None, listeners: vec![], - url: url, + url, load_origin, final_url: None, cors_setting, @@ -367,7 +362,7 @@ impl ImageCacheStore { let completed_load = CompletedLoad::new(image_response.clone(), key); self.completed_loads.insert( ( - pending_load.url.into(), + pending_load.url, pending_load.load_origin, pending_load.cors_setting, ), @@ -427,6 +422,12 @@ impl ImageCache for ImageCacheImpl { debug!("New image cache"); let rippy_data = resources::read_bytes(Resource::RippyPNG); + // Uses an estimate of the system cpus to decode images + // See https://doc.rust-lang.org/stable/std/thread/fn.available_parallelism.html + // If no information can be obtained about the system, uses 4 threads as a default + let thread_count = thread::available_parallelism() + .unwrap_or(NonZeroUsize::new(4).unwrap()) + .get(); ImageCacheImpl { store: Arc::new(Mutex::new(ImageCacheStore { @@ -434,9 +435,9 @@ impl ImageCache for ImageCacheImpl { completed_loads: HashMap::new(), placeholder_image: get_placeholder_image(&webrender_api, &rippy_data), placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(), - webrender_api: webrender_api, + webrender_api, })), - thread_pool: CoreResourceThreadPool::new(16), + thread_pool: CoreResourceThreadPool::new(thread_count), } } @@ -494,9 +495,9 @@ impl ImageCache for ImageCacheImpl { CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) { (&Some(Ok(_)), _) => { debug!("Sync decoding {} ({:?})", url, key); - decode_bytes_sync(key, &pl.bytes.as_slice(), pl.cors_status) + decode_bytes_sync(key, pl.bytes.as_slice(), pl.cors_status) }, - (&None, &Some(ref meta)) => { + (&None, Some(meta)) => { debug!("Metadata available for {} ({:?})", url, key); return ImageCacheResult::Available( ImageOrMetadataAvailable::MetadataAvailable(meta.clone()), @@ -582,7 +583,7 @@ impl ImageCache for ImageCacheImpl { fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) { match (action, id) { (FetchResponseMsg::ProcessRequestBody, _) | - (FetchResponseMsg::ProcessRequestEOF, _) => return, + (FetchResponseMsg::ProcessRequestEOF, _) => (), (FetchResponseMsg::ProcessResponse(response), _) => { debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id); let mut store = self.store.lock().unwrap(); @@ -641,7 +642,7 @@ impl ImageCache for ImageCacheImpl { let local_store = self.store.clone(); self.thread_pool.spawn(move || { - let msg = decode_bytes_sync(key, &*bytes, cors_status); + let msg = decode_bytes_sync(key, &bytes, cors_status); debug!("Image decoded"); local_store.lock().unwrap().handle_decoder(msg); }); diff --git a/components/net/mime_classifier.rs b/components/net/mime_classifier.rs index f3ced86dbc5..b4c770ba4c4 100644 --- a/components/net/mime_classifier.rs +++ b/components/net/mime_classifier.rs @@ -49,6 +49,21 @@ pub enum NoSniffFlag { Off, } +impl Default for MimeClassifier { + fn default() -> Self { + Self { + image_classifier: GroupedClassifier::image_classifer(), + audio_video_classifier: GroupedClassifier::audio_video_classifier(), + scriptable_classifier: GroupedClassifier::scriptable_classifier(), + plaintext_classifier: GroupedClassifier::plaintext_classifier(), + archive_classifier: GroupedClassifier::archive_classifier(), + binary_or_plaintext: BinaryOrPlaintextClassifier, + feeds_classifier: FeedsClassifier, + font_classifier: GroupedClassifier::font_classifier(), + } + } +} + impl MimeClassifier { //Performs MIME Type Sniffing Algorithm (sections 7 and 8) pub fn classify<'a>( @@ -164,19 +179,6 @@ impl MimeClassifier { } } - pub fn new() -> MimeClassifier { - MimeClassifier { - image_classifier: GroupedClassifier::image_classifer(), - audio_video_classifier: GroupedClassifier::audio_video_classifier(), - scriptable_classifier: GroupedClassifier::scriptable_classifier(), - plaintext_classifier: GroupedClassifier::plaintext_classifier(), - archive_classifier: GroupedClassifier::archive_classifier(), - binary_or_plaintext: BinaryOrPlaintextClassifier, - feeds_classifier: FeedsClassifier, - font_classifier: GroupedClassifier::font_classifier(), - } - } - pub fn validate(&self) -> Result<(), String> { self.image_classifier.validate()?; self.audio_video_classifier.validate()?; @@ -240,13 +242,13 @@ impl MimeClassifier { } fn get_media_type(mime: &Mime) -> Option { - if MimeClassifier::is_xml(&mime) { + if MimeClassifier::is_xml(mime) { Some(MediaType::Xml) - } else if MimeClassifier::is_html(&mime) { + } else if MimeClassifier::is_html(mime) { Some(MediaType::Html) - } else if MimeClassifier::is_image(&mime) { + } else if MimeClassifier::is_image(mime) { Some(MediaType::Image) - } else if MimeClassifier::is_audio_video(&mime) { + } else if MimeClassifier::is_audio_video(mime) { Some(MediaType::AudioVideo) } else { None @@ -256,7 +258,7 @@ impl MimeClassifier { fn maybe_get_media_type(supplied_type: &Option) -> Option { supplied_type .as_ref() - .and_then(|ref mime| MimeClassifier::get_media_type(mime)) + .and_then(MimeClassifier::get_media_type) } } @@ -338,7 +340,7 @@ impl MIMEChecker for ByteMatcher { } fn validate(&self) -> Result<(), String> { - if self.pattern.len() == 0 { + if self.pattern.is_empty() { return Err(format!("Zero length pattern for {:?}", self.content_type)); } if self.pattern.len() != self.mask.len() { @@ -436,8 +438,8 @@ impl BinaryOrPlaintextClassifier { } else if data.iter().any(|&x| { x <= 0x08u8 || x == 0x0Bu8 || - (x >= 0x0Eu8 && x <= 0x1Au8) || - (x >= 0x1Cu8 && x <= 0x1Fu8) + (0x0Eu8..=0x1Au8).contains(&x) || + (0x1Cu8..=0x1Fu8).contains(&x) }) { mime::APPLICATION_OCTET_STREAM } else { @@ -618,7 +620,7 @@ impl FeedsClassifier { // TODO: need max_bytes to prevent inadvertently examining html document // eg. an html page with a feed example loop { - if matcher.find(|&x| *x == b'<').is_none() { + if !matcher.any(|x| *x == b'<') { return None; } diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 642b158260d..032cfcb313b 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -9,7 +9,6 @@ use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufReader}; -use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, RwLock}; use std::thread; @@ -64,6 +63,7 @@ fn load_root_cert_store_from_file(file_path: String) -> io::Result, devtools_sender: Option>, @@ -103,6 +103,7 @@ pub fn new_resource_threads( } /// Create a CoreResourceThread +#[allow(clippy::too_many_arguments)] pub fn new_core_resource_thread( user_agent: Cow<'static, str>, devtools_sender: Option>, @@ -160,8 +161,8 @@ fn create_http_states( ignore_certificate_errors: bool, ) -> (Arc, Arc) { let mut hsts_list = HstsList::from_servo_preload(); - let mut auth_cache = AuthCache::new(); - let http_cache = HttpCache::new(); + let mut auth_cache = AuthCache::default(); + let http_cache = HttpCache::default(); let mut cookie_jar = CookieStorage::new(150); if let Some(config_dir) = config_dir { read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json"); @@ -189,9 +190,9 @@ fn create_http_states( let private_http_state = HttpState { hsts_list: RwLock::new(HstsList::from_servo_preload()), cookie_jar: RwLock::new(CookieStorage::new(150)), - auth_cache: RwLock::new(AuthCache::new()), + auth_cache: RwLock::new(AuthCache::default()), history_states: RwLock::new(HashMap::new()), - http_cache: RwLock::new(HttpCache::new()), + http_cache: RwLock::new(HttpCache::default()), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client(create_tls_config( ca_certificates, @@ -213,7 +214,7 @@ impl ResourceChannelManager { memory_reporter: IpcReceiver, ) { let (public_http_state, private_http_state) = create_http_states( - self.config_dir.as_ref().map(Deref::deref), + self.config_dir.as_deref(), self.ca_certificates.clone(), self.ignore_certificate_errors, ); @@ -226,9 +227,8 @@ impl ResourceChannelManager { loop { for receiver in rx_set.select().unwrap().into_iter() { // Handles case where profiler thread shuts down before resource thread. - match receiver { - ipc::IpcSelectionResult::ChannelClosed(..) => continue, - _ => {}, + if let ipc::IpcSelectionResult::ChannelClosed(..) = receiver { + continue; } let (id, data) = receiver.unwrap(); // If message is memory report, get the size_of of public and private http caches @@ -426,11 +426,10 @@ pub fn write_json_to_file(data: &T, config_dir: &Path, filename: &str) where T: Serialize, { - let json_encoded: String; - match serde_json::to_string_pretty(&data) { - Ok(d) => json_encoded = d, + let json_encoded: String = match serde_json::to_string_pretty(&data) { + Ok(d) => d, Err(_) => return, - } + }; let path = config_dir.join(filename); let display = path.display(); @@ -451,9 +450,9 @@ pub struct AuthCacheEntry { pub password: String, } -impl AuthCache { - pub fn new() -> AuthCache { - AuthCache { +impl Default for AuthCache { + fn default() -> Self { + Self { version: 1, entries: HashMap::new(), } @@ -527,11 +526,12 @@ pub struct CoreResourceThreadPool { impl CoreResourceThreadPool { pub fn new(num_threads: usize) -> CoreResourceThreadPool { let pool = rayon::ThreadPoolBuilder::new() + .thread_name(|i| format!("CoreResourceThread#{i}")) .num_threads(num_threads) .build() .unwrap(); let state = Arc::new(Mutex::new(ThreadPoolState::new())); - CoreResourceThreadPool { pool: pool, state } + CoreResourceThreadPool { pool, state } } /// Spawn work on the thread-pool, if still active. @@ -613,7 +613,7 @@ impl CoreResourceManager { let pool = CoreResourceThreadPool::new(16); let pool_handle = Arc::new(pool); CoreResourceManager { - user_agent: user_agent, + user_agent, devtools_sender, sw_managers: Default::default(), filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)), @@ -708,7 +708,7 @@ impl CoreResourceManager { let response = Response::from_init(res_init, timing_type); http_redirect_fetch( &mut request, - &mut CorsCache::new(), + &mut CorsCache::default(), response, true, &mut sender, diff --git a/components/net/storage_thread.rs b/components/net/storage_thread.rs index 07516540db9..3dcd7c19256 100644 --- a/components/net/storage_thread.rs +++ b/components/net/storage_thread.rs @@ -47,10 +47,10 @@ impl StorageManager { resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json"); } StorageManager { - port: port, + port, session_data: HashMap::new(), - local_data: local_data, - config_dir: config_dir, + local_data, + config_dir, } } } @@ -122,7 +122,7 @@ impl StorageManager { let origin = self.origin_as_string(url); let data = self.select_data(storage_type); sender - .send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len())) + .send(data.get(&origin).map_or(0, |(_, entry)| entry.len())) .unwrap(); } @@ -137,7 +137,7 @@ impl StorageManager { let data = self.select_data(storage_type); let key = data .get(&origin) - .and_then(|&(_, ref entry)| entry.keys().nth(index as usize)) + .and_then(|(_, entry)| entry.keys().nth(index as usize)) .cloned(); sender.send(key).unwrap(); } @@ -147,7 +147,7 @@ impl StorageManager { let data = self.select_data(storage_type); let keys = data .get(&origin) - .map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect()); + .map_or(vec![], |(_, entry)| entry.keys().cloned().collect()); sender.send(keys).unwrap(); } @@ -225,7 +225,7 @@ impl StorageManager { sender .send( data.get(&origin) - .and_then(|&(_, ref entry)| entry.get(&name)) + .and_then(|(_, entry)| entry.get(&name)) .map(String::clone), ) .unwrap(); @@ -244,9 +244,9 @@ impl StorageManager { let old_value = data .get_mut(&origin) .and_then(|&mut (ref mut total, ref mut entry)| { - entry.remove(&name).and_then(|old| { + entry.remove(&name).map(|old| { *total -= name.as_bytes().len() + old.as_bytes().len(); - Some(old) + old }) }); sender.send(old_value).unwrap(); diff --git a/components/net/subresource_integrity.rs b/components/net/subresource_integrity.rs index 23604d98907..04820954fa0 100644 --- a/components/net/subresource_integrity.rs +++ b/components/net/subresource_integrity.rs @@ -11,7 +11,7 @@ use generic_array::ArrayLength; use net_traits::response::{Response, ResponseBody, ResponseType}; use sha2::{Digest, Sha256, Sha384, Sha512}; -const SUPPORTED_ALGORITHM: &'static [&'static str] = &["sha256", "sha384", "sha512"]; +const SUPPORTED_ALGORITHM: &[&str] = &["sha256", "sha384", "sha512"]; pub type StaticCharVec = &'static [char]; /// A "space character" according to: /// @@ -33,7 +33,7 @@ impl SriEntry { SriEntry { alg: alg.to_owned(), val: val.to_owned(), - opt: opt, + opt, } } } @@ -46,7 +46,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec { // Step 3 let tokens = split_html_space_chars(integrity_metadata); for token in tokens { - let parsed_data: Vec<&str> = token.split("-").collect(); + let parsed_data: Vec<&str> = token.split('-').collect(); if parsed_data.len() > 1 { let alg = parsed_data[0]; @@ -55,7 +55,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec { continue; } - let data: Vec<&str> = parsed_data[1].split("?").collect(); + let data: Vec<&str> = parsed_data[1].split('?').collect(); let digest = data[0]; let opt = if data.len() > 1 { @@ -68,7 +68,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec { } } - return result; + result } /// @@ -78,11 +78,11 @@ pub fn get_prioritized_hash_function( ) -> Option { let left_priority = SUPPORTED_ALGORITHM .iter() - .position(|s| s.to_owned() == hash_func_left) + .position(|s| *s == hash_func_left) .unwrap(); let right_priority = SUPPORTED_ALGORITHM .iter() - .position(|s| s.to_owned() == hash_func_right) + .position(|s| *s == hash_func_right) .unwrap(); if left_priority == right_priority { @@ -102,7 +102,7 @@ pub fn get_strongest_metadata(integrity_metadata_list: Vec) -> Vec, D: Digest>( /// fn is_eligible_for_integrity_validation(response: &Response) -> bool { - match response.response_type { - ResponseType::Basic | ResponseType::Default | ResponseType::Cors => true, - _ => false, - } + matches!( + response.response_type, + ResponseType::Basic | ResponseType::Default | ResponseType::Cors + ) } /// @@ -174,9 +174,7 @@ pub fn is_response_integrity_valid(integrity_metadata: &str, response: &Response false } -pub fn split_html_space_chars<'a>( - s: &'a str, -) -> Filter, fn(&&str) -> bool> { +pub fn split_html_space_chars(s: &str) -> Filter, fn(&&str) -> bool> { fn not_empty(&split: &&str) -> bool { !split.is_empty() } diff --git a/components/net/tests/fetch.rs b/components/net/tests/fetch.rs index ab05a954e9e..c4409e7d6d5 100644 --- a/components/net/tests/fetch.rs +++ b/components/net/tests/fetch.rs @@ -385,7 +385,7 @@ fn test_cors_preflight_cache_fetch() { static ACK: &'static [u8] = b"ACK"; let state = Arc::new(AtomicUsize::new(0)); let counter = state.clone(); - let mut cache = CorsCache::new(); + let mut cache = CorsCache::default(); let handler = move |request: HyperRequest, response: &mut HyperResponse| { if request.method() == Method::OPTIONS && state.clone().fetch_add(1, Ordering::SeqCst) == 0 { @@ -757,7 +757,7 @@ fn test_fetch_with_hsts() { let (server, url) = make_ssl_server(handler); let mut context = FetchContext { - state: Arc::new(HttpState::new()), + state: Arc::new(HttpState::default()), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: None, filemanager: Arc::new(Mutex::new(FileManager::new( @@ -816,7 +816,7 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() { url.as_mut_url().set_scheme("https").unwrap(); let mut context = FetchContext { - state: Arc::new(HttpState::new()), + state: Arc::new(HttpState::default()), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: None, filemanager: Arc::new(Mutex::new(FileManager::new( @@ -873,7 +873,7 @@ fn test_fetch_self_signed() { url.as_mut_url().set_scheme("https").unwrap(); let mut context = FetchContext { - state: Arc::new(HttpState::new()), + state: Arc::new(HttpState::default()), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: None, filemanager: Arc::new(Mutex::new(FileManager::new( diff --git a/components/net/tests/http_cache.rs b/components/net/tests/http_cache.rs index 30a4052928a..4acdc402043 100644 --- a/components/net/tests/http_cache.rs +++ b/components/net/tests/http_cache.rs @@ -33,7 +33,7 @@ fn test_refreshing_resource_sets_done_chan_the_appropriate_value() { response .headers .insert(EXPIRES, HeaderValue::from_str("-10").unwrap()); - let mut cache = HttpCache::new(); + let mut cache = HttpCache::default(); response_bodies.iter().for_each(|body| { *response.body.lock().unwrap() = body.clone(); // First, store the 'normal' response. diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index c5eb5c7b6ff..397432735e0 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -103,7 +103,7 @@ fn new_fetch_context( let sender = fc.unwrap_or_else(|| create_embedder_proxy()); FetchContext { - state: Arc::new(HttpState::new()), + state: Arc::new(HttpState::default()), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))), filemanager: Arc::new(Mutex::new(FileManager::new( diff --git a/components/net/tests/mime_classifier.rs b/components/net/tests/mime_classifier.rs index 7301673ce16..b4e6ae6e9ab 100644 --- a/components/net/tests/mime_classifier.rs +++ b/components/net/tests/mime_classifier.rs @@ -53,7 +53,7 @@ fn test_sniff_mp4_matcher_long() { #[test] fn test_validate_classifier() { - let classifier = MimeClassifier::new(); + let classifier = MimeClassifier::default(); classifier.validate().expect("Validation error") } @@ -74,7 +74,7 @@ fn test_sniff_with_flags( let mut filename = PathBuf::from("tests/parsable_mime/"); filename.push(filename_orig); - let classifier = MimeClassifier::new(); + let classifier = MimeClassifier::default(); let read_result = read_file(&filename); diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs index 6ac7c99b6e1..1fd2b4178cb 100644 --- a/components/net/websocket_loader.rs +++ b/components/net/websocket_loader.rs @@ -94,7 +94,7 @@ fn create_request( } if resource_url.password().is_some() || resource_url.username() != "" { - let basic = base64::engine::general_purpose::STANDARD.encode(&format!( + let basic = base64::engine::general_purpose::STANDARD.encode(format!( "{}:{}", resource_url.username(), resource_url.password().unwrap_or("") @@ -147,7 +147,7 @@ fn process_ws_response( .hsts_list .write() .unwrap() - .update_hsts_list_from_response(resource_url, &response.headers()); + .update_hsts_list_from_response(resource_url, response.headers()); Ok(protocol_in_use) } @@ -389,7 +389,7 @@ fn connect( &req_url, &req_builder.origin.ascii_serialization(), &protocols, - &*http_state, + &http_state, ) { Ok(c) => c, Err(e) => return Err(e.to_string()), diff --git a/components/pixels/lib.rs b/components/pixels/lib.rs index d9a7fcc39d0..2b26af3dd7c 100644 --- a/components/pixels/lib.rs +++ b/components/pixels/lib.rs @@ -49,9 +49,7 @@ pub fn rgba8_get_rect(pixels: &[u8], size: Size2D, rect: Rect) -> Cow< pub fn rgba8_byte_swap_colors_inplace(pixels: &mut [u8]) { assert!(pixels.len() % 4 == 0); for rgba in pixels.chunks_mut(4) { - let b = rgba[0]; - rgba[0] = rgba[2]; - rgba[2] = b; + rgba.swap(0, 2); } } @@ -79,7 +77,7 @@ pub fn rgba8_premultiply_inplace(pixels: &mut [u8]) -> bool { } pub fn multiply_u8_color(a: u8, b: u8) -> u8 { - return (a as u32 * b as u32 / 255) as u8; + (a as u32 * b as u32 / 255) as u8 } pub fn clip( diff --git a/components/profile/mem.rs b/components/profile/mem.rs index 53990d7f05f..0fdeb76715c 100644 --- a/components/profile/mem.rs +++ b/components/profile/mem.rs @@ -30,8 +30,8 @@ pub struct Profiler { created: Instant, } -const JEMALLOC_HEAP_ALLOCATED_STR: &'static str = "jemalloc-heap-allocated"; -const SYSTEM_HEAP_ALLOCATED_STR: &'static str = "system-heap-allocated"; +const JEMALLOC_HEAP_ALLOCATED_STR: &str = "jemalloc-heap-allocated"; +const SYSTEM_HEAP_ALLOCATED_STR: &str = "system-heap-allocated"; impl Profiler { pub fn create(period: Option) -> ProfilerChan { @@ -84,7 +84,7 @@ impl Profiler { pub fn new(port: IpcReceiver) -> Profiler { Profiler { - port: port, + port, reporters: HashMap::new(), created: Instant::now(), } @@ -212,7 +212,7 @@ impl Profiler { println!("|"); println!("End memory reports"); - println!(""); + println!(); } } @@ -239,7 +239,7 @@ impl ReportsTree { ReportsTree { size: 0, count: 0, - path_seg: path_seg, + path_seg, children: vec![], } } @@ -259,7 +259,7 @@ impl ReportsTree { fn insert(&mut self, path: &[String], size: usize) { let mut t: &mut ReportsTree = self; for path_seg in path { - let i = match t.find_child(&path_seg) { + let i = match t.find_child(path_seg) { Some(i) => i, None => { let new_t = ReportsTree::new(path_seg.clone()); @@ -352,7 +352,7 @@ impl ReportsForest { fn print(&mut self) { // Fill in sizes of interior nodes, and recursively sort the sub-trees. - for (_, tree) in &mut self.trees { + for tree in self.trees.values_mut() { tree.compute_interior_node_sizes_and_sort(); } @@ -360,7 +360,7 @@ impl ReportsForest { // single node) come after non-degenerate trees. Secondary sort: alphabetical order of the // root node's path_seg. let mut v = vec![]; - for (_, tree) in &self.trees { + for tree in self.trees.values() { v.push(tree); } v.sort_by(|a, b| { @@ -412,9 +412,9 @@ mod system_reporter { let mut report = |path, size| { if let Some(size) = size { reports.push(Report { - path: path, + path, kind: ReportKind::NonExplicitSize, - size: size, + size, }); } }; @@ -663,7 +663,7 @@ mod system_reporter { // Construct the segment name from its pathname and permissions. curr_seg_name.clear(); - if pathname == "" || pathname.starts_with("[stack:") { + if pathname.is_empty() || pathname.starts_with("[stack:") { // Anonymous memory. Entries marked with "[stack:nnn]" // look like thread stacks but they may include other // anonymous mappings, so we can't trust them and just @@ -674,7 +674,7 @@ mod system_reporter { } curr_seg_name.push_str(" ("); curr_seg_name.push_str(perms); - curr_seg_name.push_str(")"); + curr_seg_name.push(')'); looking_for = LookingFor::Rss; } else { diff --git a/components/profile/time.rs b/components/profile/time.rs index e54542b9a8a..f07e273735d 100644 --- a/components/profile/time.rs +++ b/components/profile/time.rs @@ -184,9 +184,9 @@ impl Profiler { }) .expect("Thread spawning failed"); // decide if we need to spawn the timer thread - match option { - &OutputOptions::FileName(_) => { /* no timer thread needed */ }, - &OutputOptions::Stdout(period) => { + match *option { + OutputOptions::FileName(_) => { /* no timer thread needed */ }, + OutputOptions::Stdout(period) => { // Spawn a timer thread let chan = chan.clone(); thread::Builder::new() @@ -241,11 +241,11 @@ impl Profiler { output: Option, ) -> Profiler { Profiler { - port: port, + port, buckets: BTreeMap::new(), - output: output, + output, last_msg: None, - trace: trace, + trace, blocked_layout_queries: HashMap::new(), } } @@ -259,7 +259,7 @@ impl Profiler { } fn find_or_insert(&mut self, k: (ProfilerCategory, Option), t: f64) { - self.buckets.entry(k).or_insert_with(Vec::new).push(t); + self.buckets.entry(k).or_default().push(t); } fn handle_msg(&mut self, msg: ProfilerMsg) -> bool { @@ -321,24 +321,24 @@ impl Profiler { match self.output { Some(OutputOptions::FileName(ref filename)) => { let path = Path::new(&filename); - let mut file = match File::create(&path) { + let mut file = match File::create(path) { Err(e) => panic!("Couldn't create {}: {}", path.display(), e), Ok(file) => file, }; - write!( + writeln!( file, "_category_\t_incremental?_\t_iframe?_\t_url_\t_mean (ms)_\t\ - _median (ms)_\t_min (ms)_\t_max (ms)_\t_events_\n" + _median (ms)_\t_min (ms)_\t_max (ms)_\t_events_" ) .unwrap(); - for (&(ref category, ref meta), ref mut data) in &mut self.buckets { + for ((category, meta), ref mut data) in &mut self.buckets { data.sort_by(|a, b| a.partial_cmp(b).expect("No NaN values in profiles")); let data_len = data.len(); if data_len > 0 { let (mean, median, min, max) = Self::get_statistics(data); - write!( + writeln!( file, - "{}\t{}\t{:15.4}\t{:15.4}\t{:15.4}\t{:15.4}\t{:15}\n", + "{}\t{}\t{:15.4}\t{:15.4}\t{:15.4}\t{:15.4}\t{:15}", category.format(&self.output), meta.format(&self.output), mean, @@ -351,9 +351,9 @@ impl Profiler { } } - write!(file, "_url\t_blocked layout queries_\n").unwrap(); + writeln!(file, "_url\t_blocked layout queries_").unwrap(); for (url, count) in &self.blocked_layout_queries { - write!(file, "{}\t{}\n", url, count).unwrap(); + writeln!(file, "{}\t{}", url, count).unwrap(); } }, Some(OutputOptions::Stdout(_)) => { @@ -374,7 +374,7 @@ impl Profiler { " _events_" ) .unwrap(); - for (&(ref category, ref meta), ref mut data) in &mut self.buckets { + for ((category, meta), ref mut data) in &mut self.buckets { data.sort_by(|a, b| a.partial_cmp(b).expect("No NaN values in profiles")); let data_len = data.len(); if data_len > 0 { @@ -393,13 +393,13 @@ impl Profiler { .unwrap(); } } - writeln!(&mut lock, "").unwrap(); + writeln!(&mut lock).unwrap(); writeln!(&mut lock, "_url_\t_blocked layout queries_").unwrap(); for (url, count) in &self.blocked_layout_queries { writeln!(&mut lock, "{}\t{}", url, count).unwrap(); } - writeln!(&mut lock, "").unwrap(); + writeln!(&mut lock).unwrap(); }, None => { /* Do nothing if no output option has been set */ }, }; diff --git a/components/profile/trace_dump.rs b/components/profile/trace_dump.rs index 3051e08ee11..66614a28b98 100644 --- a/components/profile/trace_dump.rs +++ b/components/profile/trace_dump.rs @@ -37,7 +37,7 @@ impl TraceDump { { let mut file = fs::File::create(trace_file_path)?; write_prologue(&mut file)?; - Ok(TraceDump { file: file }) + Ok(TraceDump { file }) } /// Write one trace to the trace dump file. diff --git a/components/range/lib.rs b/components/range/lib.rs index 6b98b68a658..8c5ca095f53 100644 --- a/components/range/lib.rs +++ b/components/range/lib.rs @@ -204,10 +204,7 @@ impl Range { /// ~~~ #[inline] pub fn new(begin: I, length: I) -> Range { - Range { - begin: begin, - length: length, - } + Range { begin, length } } #[inline] diff --git a/components/remutex/lib.rs b/components/remutex/lib.rs index 94efae26199..9ee51305a45 100644 --- a/components/remutex/lib.rs +++ b/components/remutex/lib.rs @@ -36,7 +36,7 @@ impl ThreadId { ThreadId(NonZeroUsize::new(number).unwrap()) } pub fn current() -> ThreadId { - THREAD_ID.with(|tls| tls.clone()) + THREAD_ID.with(|tls| *tls) } } @@ -46,10 +46,13 @@ thread_local! { static THREAD_ID: ThreadId = ThreadId::new() } #[derive(Debug)] pub struct AtomicOptThreadId(AtomicUsize); -impl AtomicOptThreadId { - pub fn new() -> AtomicOptThreadId { +impl Default for AtomicOptThreadId { + fn default() -> Self { AtomicOptThreadId(AtomicUsize::new(0)) } +} + +impl AtomicOptThreadId { pub fn store(&self, value: Option, ordering: Ordering) { let number = value.map(|id| id.0.get()).unwrap_or(0); self.0.store(number, ordering); @@ -75,14 +78,17 @@ pub struct HandOverHandMutex { guard: UnsafeCell>>, } -impl HandOverHandMutex { - pub fn new() -> HandOverHandMutex { - HandOverHandMutex { +impl Default for HandOverHandMutex { + fn default() -> Self { + Self { mutex: Mutex::new(()), - owner: AtomicOptThreadId::new(), + owner: AtomicOptThreadId::default(), guard: UnsafeCell::new(None), } } +} + +impl HandOverHandMutex { #[allow(unsafe_code)] unsafe fn set_guard_and_owner<'a>(&'a self, guard: MutexGuard<'a, ()>) { // The following two lines allow us to unsafely store @@ -107,7 +113,7 @@ impl HandOverHandMutex { assert_eq!(old_owner, Some(ThreadId::current())); } #[allow(unsafe_code)] - pub fn lock<'a>(&'a self) -> LockResult<()> { + pub fn lock(&self) -> LockResult<()> { let (guard, result) = match self.mutex.lock() { Ok(guard) => (guard, Ok(())), Err(err) => (err.into_inner(), Err(PoisonError::new(()))), @@ -163,9 +169,9 @@ impl ReentrantMutex { pub fn new(data: T) -> ReentrantMutex { trace!("{:?} Creating new lock.", ThreadId::current()); ReentrantMutex { - mutex: HandOverHandMutex::new(), + mutex: HandOverHandMutex::default(), count: Cell::new(0), - data: data, + data, } } @@ -173,7 +179,7 @@ impl ReentrantMutex { trace!("{:?} Locking.", ThreadId::current()); if self.mutex.owner() != Some(ThreadId::current()) { trace!("{:?} Becoming owner.", ThreadId::current()); - if let Err(_) = self.mutex.lock() { + if self.mutex.lock().is_err() { trace!("{:?} Poison!", ThreadId::current()); return Err(PoisonError::new(self.mk_guard())); } diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index a9d2d52b94e..1fc2f1a69cc 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -22,8 +22,8 @@ refcell_backtrace = ["accountable-refcell"] xr-profile = ["webxr-api/profile"] [build-dependencies] -phf_codegen = "0.10" -phf_shared = "0.10" +phf_codegen = "0.11" +phf_shared = "0.11" serde_json = { workspace = true } [dependencies] diff --git a/components/script/build.rs b/components/script/build.rs index 3fabbeee1fa..d002cdb6982 100644 --- a/components/script/build.rs +++ b/components/script/build.rs @@ -31,16 +31,16 @@ fn main() { println!("Binding generation completed in {:?}", start.elapsed()); let json = out_dir.join("InterfaceObjectMapData.json"); - let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap(); + let json: Value = serde_json::from_reader(File::open(json).unwrap()).unwrap(); let mut map = phf_codegen::Map::new(); for (key, value) in json.as_object().unwrap() { map.entry(Bytes(key), value.as_str().unwrap()); } let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs"); - let mut phf = File::create(&phf).unwrap(); - write!( + let mut phf = File::create(phf).unwrap(); + writeln!( &mut phf, - "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};\n", + "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};", map.build(), ) .unwrap(); diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index 7f2545f3934..2e1b2bd6b06 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -44,7 +44,7 @@ pub struct AudioBuffer { #[ignore_malloc_size_of = "mozjs"] js_channels: DomRefCell>>, /// Aggregates the data from js_channels. - /// This is Some iff the buffers in js_channels are detached. + /// This is `Some` iff the buffers in js_channels are detached. #[ignore_malloc_size_of = "servo_media"] #[no_trace] shared_channels: DomRefCell>, diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 9a8dee594c8..b0ea79ae4e6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6101,38 +6101,12 @@ let this = native_from_object_static::<%s>(obj).unwrap(); def finalizeHook(descriptor, hookName, context): - release = "" if descriptor.isGlobal(): - release += """\ -finalize_global(obj); -""" + release = "finalize_global(obj, this);" elif descriptor.weakReferenceable: - release += """\ -let mut slot = UndefinedValue(); -JS_GetReservedSlot(obj, DOM_WEAK_SLOT, &mut slot); -let weak_box_ptr = slot.to_private() as *mut WeakBox<%s>; -if !weak_box_ptr.is_null() { - let count = { - let weak_box = &*weak_box_ptr; - assert!(weak_box.value.get().is_some()); - assert!(weak_box.count.get() > 0); - weak_box.value.set(None); - let count = weak_box.count.get() - 1; - weak_box.count.set(count); - count - }; - if count == 0 { - mem::drop(Box::from_raw(weak_box_ptr)); - } -} -""" % descriptor.concreteType - release += """\ -if !this.is_null() { - // The pointer can be null if the object is the unforgeable holder of that interface. - let _ = Box::from_raw(this as *mut %s); -} -debug!("%s finalize: {:p}", this);\ -""" % (descriptor.concreteType, descriptor.concreteType) + release = "finalize_weak_referenceable(obj, this);" + else: + release = "finalize_common(this);" return release @@ -6186,8 +6160,9 @@ let global = DomRoot::downcast::(global).unwrap(); cx, &args, &*global, - GetProtoObject, - )""" % self.descriptor.name) + PrototypeList::ID::%s, + CreateInterfaceObjects, + )""" % (self.descriptor.name, MakeNativeName(self.descriptor.name))) else: ctorName = GetConstructorNameForReporting(self.descriptor, self.constructor) preamble += """ @@ -6569,7 +6544,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::utils::ProtoOrIfaceArray', 'crate::dom::bindings::utils::callargs_is_constructing', 'crate::dom::bindings::utils::enumerate_global', - 'crate::dom::bindings::utils::finalize_global', + 'crate::dom::bindings::finalize::finalize_common', + 'crate::dom::bindings::finalize::finalize_global', + 'crate::dom::bindings::finalize::finalize_weak_referenceable', 'crate::dom::bindings::utils::generic_getter', 'crate::dom::bindings::utils::generic_lenient_getter', 'crate::dom::bindings::utils::generic_lenient_setter', diff --git a/components/script/dom/bindings/finalize.rs b/components/script/dom/bindings/finalize.rs new file mode 100644 index 00000000000..9ef4665118a --- /dev/null +++ b/components/script/dom/bindings/finalize.rs @@ -0,0 +1,52 @@ +/* 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::any::type_name; +use std::mem; + +use js::glue::JS_GetReservedSlot; +use js::jsapi::JSObject; +use js::jsval::UndefinedValue; + +use crate::dom::bindings::utils::finalize_global as do_finalize_global; +use crate::dom::bindings::weakref::{WeakBox, WeakReferenceable, DOM_WEAK_SLOT}; + +/// Generic finalizer implementations for DOM binding implementations. + +pub unsafe fn finalize_common(this: *const T) { + if !this.is_null() { + // The pointer can be null if the object is the unforgeable holder of that interface. + let _ = Box::from_raw(this as *mut T); + } + debug!("{} finalize: {:p}", type_name::(), this); +} + +pub unsafe fn finalize_global(obj: *mut JSObject, this: *const T) { + do_finalize_global(obj); + finalize_common::(this); +} + +pub unsafe fn finalize_weak_referenceable( + obj: *mut JSObject, + this: *const T, +) { + let mut slot = UndefinedValue(); + JS_GetReservedSlot(obj, DOM_WEAK_SLOT, &mut slot); + let weak_box_ptr = slot.to_private() as *mut WeakBox; + if !weak_box_ptr.is_null() { + let count = { + let weak_box = &*weak_box_ptr; + assert!(weak_box.value.get().is_some()); + assert!(weak_box.count.get() > 0); + weak_box.value.set(None); + let count = weak_box.count.get() - 1; + weak_box.count.set(count); + count + }; + if count == 0 { + mem::drop(Box::from_raw(weak_box_ptr)); + } + } + finalize_common::(this); +} diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index 703bfeb7c70..d34ee6eba0b 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -9,10 +9,10 @@ use html5ever::{local_name, namespace_url, ns, LocalName}; use js::conversions::ToJSValConvertible; use js::glue::{UnwrapObjectDynamic, UnwrapObjectStatic}; use js::jsapi::{CallArgs, CurrentGlobalOrNull, JSAutoRealm, JSObject}; -use js::jsval::UndefinedValue; -use js::rust::wrappers::{JS_GetProperty, JS_SetPrototype, JS_WrapObject}; +use js::rust::wrappers::{JS_SetPrototype, JS_WrapObject}; use js::rust::{HandleObject, MutableHandleObject, MutableHandleValue}; +use super::utils::ProtoOrIfaceArray; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::{ HTMLAnchorElementBinding, HTMLAreaElementBinding, HTMLAudioElementBinding, @@ -38,9 +38,11 @@ use crate::dom::bindings::codegen::Bindings::{ HTMLTimeElementBinding, HTMLTitleElementBinding, HTMLTrackElementBinding, HTMLUListElementBinding, HTMLVideoElementBinding, }; +use crate::dom::bindings::codegen::PrototypeList; use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::error::{throw_dom_exception, Error}; use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::interface::get_desired_proto; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; use crate::dom::create::create_native_html_element; @@ -49,7 +51,7 @@ use crate::dom::element::{Element, ElementCreator}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::window::Window; -use crate::script_runtime::JSContext; +use crate::script_runtime::{JSContext, JSContext as SafeJSContext}; use crate::script_thread::ScriptThread; // https://html.spec.whatwg.org/multipage/#htmlconstructor @@ -58,7 +60,8 @@ unsafe fn html_constructor( window: &Window, call_args: &CallArgs, check_type: fn(&Element) -> bool, - get_proto_object: fn(JSContext, HandleObject, MutableHandleObject), + proto_id: PrototypeList::ID, + creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), ) -> Result<(), ()> { let document = window.Document(); let global = window.upcast::(); @@ -142,40 +145,7 @@ unsafe fn html_constructor( // Step 6 rooted!(in(*cx) let mut prototype = ptr::null_mut::()); - { - rooted!(in(*cx) let mut proto_val = UndefinedValue()); - let _ac = JSAutoRealm::new(*cx, new_target_unwrapped.get()); - if !JS_GetProperty( - *cx, - new_target_unwrapped.handle(), - b"prototype\0".as_ptr() as *const _, - proto_val.handle_mut(), - ) { - return Err(()); - } - - if !proto_val.is_object() { - // Step 7 of https://html.spec.whatwg.org/multipage/#htmlconstructor. - // This fallback behavior is designed to match analogous behavior for the - // JavaScript built-ins. So we enter the realm of our underlying - // newTarget object and fall back to the prototype object from that global. - // XXX The spec says to use GetFunctionRealm(), which is not actually - // the same thing as what we have here (e.g. in the case of scripted callable proxies - // whose target is not same-realm with the proxy, or bound functions, etc). - // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 - - rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx)); - get_proto_object(cx, global_object.handle(), prototype.handle_mut()); - } else { - // Step 6 - prototype.set(proto_val.to_object()); - } - } - - // Wrap prototype in this context since it is from the newTarget realm - if !JS_WrapObject(*cx, prototype.handle_mut()) { - return Err(()); - } + get_desired_proto(cx, &call_args, proto_id, creator, prototype.handle_mut())?; let entry = definition.construction_stack.borrow().last().cloned(); let result = match entry { @@ -251,8 +221,10 @@ unsafe fn html_constructor( Ok(()) } -/// Returns the constructor object for the element associated with the given local name. -/// This list should only include elements marked with the [HTMLConstructor] extended attribute. +/// Returns the constructor object for the element associated with the +/// given local name. This list should only include elements marked with the +/// [HTMLConstructor](https://html.spec.whatwg.org/multipage/#htmlconstructor) +/// extended attribute. pub fn get_constructor_object_from_local_name( name: LocalName, cx: JSContext, @@ -409,7 +381,8 @@ pub(crate) unsafe fn call_html_constructor + DomObject>( cx: JSContext, args: &CallArgs, global: &Window, - get_proto_object: fn(JSContext, HandleObject, MutableHandleObject), + proto_id: PrototypeList::ID, + creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), ) -> bool { fn element_derives_interface>(element: &Element) -> bool { element.is::() @@ -420,7 +393,8 @@ pub(crate) unsafe fn call_html_constructor + DomObject>( global, args, element_derives_interface::, - get_proto_object, + proto_id, + creator, ) .is_ok() } diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index 9733cabc73e..82608367aef 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -140,6 +140,7 @@ pub mod cell; pub mod constant; pub mod conversions; pub mod error; +pub mod finalize; pub mod guard; pub mod htmlconstructor; pub mod inheritance; diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs index 3bf2dcef22e..e03534147fd 100644 --- a/components/script/dom/bindings/refcounted.rs +++ b/components/script/dom/bindings/refcounted.rs @@ -68,7 +68,7 @@ impl TrustedReference { /// A safe wrapper around a DOM Promise object that can be shared among threads for use /// in asynchronous operations. The underlying DOM object is guaranteed to live at least /// as long as the last outstanding `TrustedPromise` instance. These values cannot be cloned, -/// only created from existing Rc values. +/// only created from existing `Rc` values. pub struct TrustedPromise { dom_object: *const Promise, owner_thread: *const libc::c_void, diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs index 081fe38312b..eefeb04e94d 100644 --- a/components/script/dom/bindings/reflector.rs +++ b/components/script/dom/bindings/reflector.rs @@ -135,7 +135,7 @@ pub trait DomObjectWrap: Sized + DomObject { /// A trait to provide a function pointer to wrap function for /// DOM iterator interfaces. pub trait DomObjectIteratorWrap: DomObjectWrap + JSTraceable + Iterable { - /// Function pointer to the wrap function for IterableIterator + /// Function pointer to the wrap function for `IterableIterator` const ITER_WRAP: unsafe fn( JSContext, &GlobalScope, diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs index f97306784ed..38dbfde38cf 100644 --- a/components/script/dom/bindings/str.rs +++ b/components/script/dom/bindings/str.rs @@ -151,9 +151,9 @@ pub fn is_token(s: &[u8]) -> bool { /// A DOMString. /// -/// This type corresponds to the [`DOMString`](idl) type in WebIDL. +/// This type corresponds to the [`DOMString`] type in WebIDL. /// -/// [idl]: https://heycam.github.io/webidl/#idl-DOMString +/// [`DOMString`]: https://webidl.spec.whatwg.org/#idl-DOMString /// /// Conceptually, a DOMString has the same value space as a JavaScript String, /// i.e., an array of 16-bit *code units* representing UTF-16, potentially with diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 019cc07529f..763cd4bf989 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1174,7 +1174,7 @@ impl Document { kind, text, multiline, - DeviceIntRect::from_untyped(&rect), + DeviceIntRect::from_untyped(&rect.to_box2d()), )); } } @@ -3200,7 +3200,7 @@ impl Document { fullscreen_element: MutNullableDom::new(None), form_id_listener_map: Default::default(), interactive_time: DomRefCell::new(interactive_time), - tti_window: DomRefCell::new(InteractiveWindow::new()), + tti_window: DomRefCell::new(InteractiveWindow::default()), canceller: canceller, throw_on_dynamic_markup_insertion_counter: Cell::new(0), page_showing: Cell::new(false), @@ -3547,7 +3547,7 @@ impl Document { RefMut::map(map, |m| { &mut m .entry(Dom::from_ref(el)) - .or_insert_with(|| NoTrace(PendingRestyle::new())) + .or_insert_with(|| NoTrace(PendingRestyle::default())) .0 }) } diff --git a/components/script/dom/gamepad.rs b/components/script/dom/gamepad.rs index 2cf327cd06e..68e7a1de2e5 100644 --- a/components/script/dom/gamepad.rs +++ b/components/script/dom/gamepad.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use dom_struct::dom_struct; use js::typedarray::{Float64, Float64Array}; +use script_traits::GamepadUpdateType; use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::GamepadBinding::{GamepadHand, GamepadMethods}; @@ -23,6 +24,9 @@ use crate::dom::gamepadpose::GamepadPose; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::JSContext; +// This value is for determining when to consider a gamepad as having a user gesture +// from an axis tilt. This matches the threshold in Chromium. +const AXIS_TILT_THRESHOLD: f64 = 0.5; // This value is for determining when to consider a non-digital button "pressed". // Like Gecko and Chromium it derives from the XInput trigger threshold. const BUTTON_PRESS_THRESHOLD: f64 = 30.0 / 255.0; @@ -44,6 +48,7 @@ pub struct Gamepad { hand: GamepadHand, axis_bounds: (f64, f64), button_bounds: (f64, f64), + exposed: Cell, } impl Gamepad { @@ -74,6 +79,7 @@ impl Gamepad { hand: hand, axis_bounds: axis_bounds, button_bounds: button_bounds, + exposed: Cell::new(false), } } @@ -105,7 +111,7 @@ impl Gamepad { gamepad_id, id, 0, - false, + true, 0., String::from("standard"), &button_list, @@ -175,7 +181,7 @@ impl Gamepad { self.gamepad_id } - pub fn update_connected(&self, connected: bool) { + pub fn update_connected(&self, connected: bool, has_gesture: bool) { if self.connected.get() == connected { return; } @@ -187,7 +193,9 @@ impl Gamepad { GamepadEventType::Disconnected }; - self.notify_event(event_type); + if has_gesture { + self.notify_event(event_type); + } } pub fn update_index(&self, index: i32) { @@ -263,4 +271,26 @@ impl Gamepad { warn!("Button bounds difference is either 0 or non-finite!"); } } + + /// + pub fn exposed(&self) -> bool { + self.exposed.get() + } + + /// + pub fn set_exposed(&self, exposed: bool) { + self.exposed.set(exposed); + } +} + +/// +pub fn contains_user_gesture(update_type: GamepadUpdateType) -> bool { + match update_type { + GamepadUpdateType::Axis(_, value) => { + return value.abs() > AXIS_TILT_THRESHOLD; + }, + GamepadUpdateType::Button(_, value) => { + return value > BUTTON_PRESS_THRESHOLD; + }, + }; } diff --git a/components/script/dom/gamepadlist.rs b/components/script/dom/gamepadlist.rs index 4f373e24d96..5efa99f7aa8 100644 --- a/components/script/dom/gamepadlist.rs +++ b/components/script/dom/gamepadlist.rs @@ -48,6 +48,14 @@ impl GamepadList { pub fn remove_gamepad(&self, index: usize) { self.list.borrow_mut().remove(index); } + + pub fn list(&self) -> Vec>> { + self.list + .borrow() + .iter() + .map(|gamepad| Some(DomRoot::from_ref(&**gamepad))) + .collect() + } } impl GamepadListMethods for GamepadList { diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index cb8bb72a7fd..c9fd013318c 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -67,7 +67,6 @@ use crate::dom::bindings::codegen::Bindings::GamepadListBinding::GamepadList_Bin use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{ ImageBitmapOptions, ImageBitmapSource, }; -use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::PerformanceBinding::Performance_Binding::PerformanceMethods; use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState; use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction; @@ -95,7 +94,8 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::eventsource::EventSource; use crate::dom::eventtarget::EventTarget; use crate::dom::file::File; -use crate::dom::gamepad::Gamepad; +use crate::dom::gamepad::{contains_user_gesture, Gamepad}; +use crate::dom::gamepadevent::GamepadEventType; use crate::dom::gpudevice::GPUDevice; use crate::dom::htmlscriptelement::{ScriptId, SourceCode}; use crate::dom::identityhub::Identities; @@ -3136,42 +3136,43 @@ impl GlobalScope { // TODO: 2. If document is not null and is not allowed to use the "gamepad" permission, // then abort these steps. let this = Trusted::new(&*self); - self.gamepad_task_source().queue( + self.gamepad_task_source().queue_with_canceller( task!(gamepad_connected: move || { let global = this.root(); let gamepad = Gamepad::new(&global, index as u32, name, axis_bounds, button_bounds); if let Some(window) = global.downcast::() { - let gamepad_list = window.Navigator().GetGamepads(); + let has_gesture = window.Navigator().has_gamepad_gesture(); + if has_gesture { + gamepad.set_exposed(true); + if window.Document().is_fully_active() { + gamepad.update_connected(true, has_gesture); + } + } + let gamepad_list = window.Navigator().gamepads(); let gamepad_arr: [DomRoot; 1] = [gamepad.clone()]; gamepad_list.add_if_not_exists(&gamepad_arr); - - // TODO: 3.4 If navigator.[[hasGamepadGesture]] is true: - // TODO: 3.4.1 Set gamepad.[[exposed]] to true. - - if window.Document().is_fully_active() { - gamepad.update_connected(true); - } } }), - &self, + &self.task_canceller(TaskSourceName::Gamepad) ) - .unwrap(); + .expect("Failed to queue gamepad connected task."); } /// pub fn handle_gamepad_disconnect(&self, index: usize) { let this = Trusted::new(&*self); self.gamepad_task_source() - .queue( + .queue_with_canceller( task!(gamepad_disconnected: move || { let global = this.root(); if let Some(window) = global.downcast::() { - let gamepad_list = window.Navigator().GetGamepads(); + let gamepad_list = window.Navigator().gamepads(); if let Some(gamepad) = gamepad_list.Item(index as u32) { - // TODO: If gamepad.[[exposed]] - gamepad.update_connected(false); - gamepad_list.remove_gamepad(index); + if window.Document().is_fully_active() { + gamepad.update_connected(false, gamepad.exposed()); + gamepad_list.remove_gamepad(index); + } } for i in (0..gamepad_list.Length()).rev() { if gamepad_list.Item(i as u32).is_none() { @@ -3182,9 +3183,9 @@ impl GlobalScope { } } }), - &self, + &self.task_canceller(TaskSourceName::Gamepad), ) - .unwrap(); + .expect("Failed to queue gamepad disconnected task."); } /// @@ -3193,12 +3194,12 @@ impl GlobalScope { // self.gamepad_task_source() - .queue( + .queue_with_canceller( task!(update_gamepad_state: move || { let global = this.root(); if let Some(window) = global.downcast::() { - let gamepad_list = window.Navigator().GetGamepads(); - if let Some(gamepad) = gamepad_list.IndexedGetter(index as u32) { + let gamepad_list = window.Navigator().gamepads(); + if let Some(gamepad) = gamepad_list.Item(index as u32) { let current_time = global.performance().Now(); gamepad.update_timestamp(*current_time); @@ -3211,14 +3212,32 @@ impl GlobalScope { } }; - // TODO: 6. If navigator.[[hasGamepadGesture]] is false - // and gamepad contains a gamepad user gesture: + if !window.Navigator().has_gamepad_gesture() && contains_user_gesture(update_type) { + window.Navigator().set_has_gamepad_gesture(true); + for i in 0..gamepad_list.Length() { + if let Some(gamepad) = gamepad_list.Item(i as u32) { + gamepad.set_exposed(true); + gamepad.update_timestamp(*current_time); + let new_gamepad = Trusted::new(&*gamepad); + if window.Document().is_fully_active() { + window.task_manager().gamepad_task_source().queue_with_canceller( + task!(update_gamepad_connect: move || { + let gamepad = new_gamepad.root(); + gamepad.notify_event(GamepadEventType::Connected); + }), + &window.upcast::().task_canceller(TaskSourceName::Gamepad), + ) + .expect("Failed to queue update gamepad connect task."); + } + } + } + } } } }), - &self, + &self.task_canceller(TaskSourceName::Gamepad), ) - .unwrap(); + .expect("Failed to queue update gamepad state task."); } pub(crate) fn current_group_label(&self) -> Option { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 994691d956f..d5860aaf70d 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -9,7 +9,7 @@ use std::ptr::NonNull; use std::{f64, ptr}; use chrono::naive::{NaiveDate, NaiveDateTime}; -use chrono::{Datelike, Weekday}; +use chrono::{DateTime, Datelike, Weekday}; use dom_struct::dom_struct; use embedder_traits::FilterPattern; use encoding_rs::Encoding; @@ -1327,7 +1327,7 @@ impl HTMLInputElementMethods for HTMLInputElement { self.convert_string_to_naive_datetime(self.Value()) .map(|dt| unsafe { let time = ClippedTime { - t: dt.timestamp_millis() as f64, + t: dt.and_utc().timestamp_millis() as f64, }; NonNull::new_unchecked(NewDateObject(*cx, time)) }) @@ -2145,7 +2145,7 @@ impl HTMLInputElement { .ok() .and_then(|(year, month, day)| NaiveDate::from_ymd_opt(year, month, day)) .and_then(|date| date.and_hms_opt(0, 0, 0)) - .map(|time| Ok(time.timestamp_millis() as f64)) + .map(|time| Ok(time.and_utc().timestamp_millis() as f64)) .unwrap_or(Err(())), InputType::Month => match value.parse_month_string() { // This one returns number of months, not milliseconds @@ -2160,7 +2160,7 @@ impl HTMLInputElement { .ok() .and_then(|(year, weeknum)| NaiveDate::from_isoywd_opt(year, weeknum, Weekday::Mon)) .and_then(|date| date.and_hms_opt(0, 0, 0)) - .map(|time| Ok(time.timestamp_millis() as f64)) + .map(|time| Ok(time.and_utc().timestamp_millis() as f64)) .unwrap_or(Err(())), InputType::Time => match value.parse_time_string() { Ok((hours, minutes, seconds)) => { @@ -2178,7 +2178,7 @@ impl HTMLInputElement { (seconds + 60.0 * minutes as f64 + 3600.0 * hours as f64) * 1000.0; NaiveDate::from_ymd_opt(year, month, day) .and_then(|date| date.and_hms_opt(0, 0, 0)) - .map(|time| Ok(time.timestamp_millis() as f64 + hms_millis)) + .map(|time| Ok(time.and_utc().timestamp_millis() as f64 + hms_millis)) }) .unwrap_or(Err(())) }, @@ -2916,7 +2916,10 @@ fn milliseconds_to_datetime(value: f64) -> Result { let seconds = (value / 1000.0).floor(); let milliseconds = value - (seconds * 1000.0); let nanoseconds = milliseconds * 1e6; - NaiveDateTime::from_timestamp_opt(seconds as i64, nanoseconds as u32).ok_or(()) + match DateTime::from_timestamp(seconds as i64, nanoseconds as u32) { + Some(datetime) => Ok(datetime.naive_utc()), + None => Err(()), + } } // This is used to compile JS-compatible regex provided in pattern attribute diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index ad7977000fe..a42355167e9 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -276,8 +276,21 @@ impl StylesheetOwner for HTMLStyleElement { } impl HTMLStyleElementMethods for HTMLStyleElement { - // https://drafts.csswg.org/cssom/#dom-linkstyle-sheet + /// fn GetSheet(&self) -> Option> { self.get_cssom_stylesheet().map(DomRoot::upcast) } + + /// + fn Disabled(&self) -> bool { + self.get_cssom_stylesheet() + .map_or(false, |sheet| sheet.disabled()) + } + + /// + fn SetDisabled(&self, value: bool) { + if let Some(sheet) = self.get_cssom_stylesheet() { + sheet.set_disabled(value); + } + } } diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 612d2e68ff4..d16b4f263ae 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -2,6 +2,7 @@ * 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::convert::TryInto; use dom_struct::dom_struct; @@ -9,11 +10,13 @@ use js::jsval::JSVal; use lazy_static::lazy_static; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; +use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::bindings::utils::to_frozen_array; use crate::dom::bluetooth::Bluetooth; +use crate::dom::gamepad::Gamepad; use crate::dom::gamepadlist::GamepadList; use crate::dom::gpu::GPU; use crate::dom::mediadevices::MediaDevices; @@ -43,10 +46,13 @@ pub struct Navigator { service_worker: MutNullableDom, xr: MutNullableDom, mediadevices: MutNullableDom, + /// gamepads: MutNullableDom, permissions: MutNullableDom, mediasession: MutNullableDom, gpu: MutNullableDom, + /// + has_gamepad_gesture: Cell, } impl Navigator { @@ -63,6 +69,7 @@ impl Navigator { permissions: Default::default(), mediasession: Default::default(), gpu: Default::default(), + has_gamepad_gesture: Cell::new(false), } } @@ -73,6 +80,21 @@ impl Navigator { pub fn xr(&self) -> Option> { self.xr.get() } + + pub fn gamepads(&self) -> DomRoot { + let gamepads = self + .gamepads + .or_init(|| GamepadList::new(&self.global(), &[])); + gamepads + } + + pub fn has_gamepad_gesture(&self) -> bool { + self.has_gamepad_gesture.get() + } + + pub fn set_has_gamepad_gesture(&self, has_gamepad_gesture: bool) { + self.has_gamepad_gesture.set(has_gamepad_gesture); + } } impl NavigatorMethods for Navigator { @@ -169,14 +191,20 @@ impl NavigatorMethods for Navigator { true } - // https://www.w3.org/TR/gamepad/#navigator-interface-extension - fn GetGamepads(&self) -> DomRoot { - let root = self - .gamepads - .or_init(|| GamepadList::new(&self.global(), &[])); + /// + fn GetGamepads(&self) -> Vec>> { + let global = self.global(); + let window = global.as_window(); + let doc = window.Document(); - // TODO: Add gamepads - root + // TODO: Handle permissions policy once implemented + if !doc.is_fully_active() || !self.has_gamepad_gesture.get() { + return Vec::new(); + } + + let root = self.gamepads.or_init(|| GamepadList::new(&global, &[])); + + root.list() } // https://w3c.github.io/permissions/#navigator-and-workernavigator-extension fn Permissions(&self) -> DomRoot { diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index b0274ebeb2a..feeef281041 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -53,7 +53,7 @@ pub struct Promise { permanent_js_root: Heap, } -/// Private helper to enable adding new methods to Rc. +/// Private helper to enable adding new methods to `Rc`. trait PromiseHelper { fn initialize(&self, cx: SafeJSContext); } diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index bb450a32296..82f2f737823 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -1281,7 +1281,7 @@ impl TreeSink for Sink { } /// - /// Specifically, the cases. + /// Specifically, the `` cases. fn is_mathml_annotation_xml_integration_point(&self, handle: &Dom) -> bool { let elem = handle.downcast::().unwrap(); elem.get_attribute(&ns!(), &local_name!("encoding")) diff --git a/components/script/dom/webidls/HTMLStyleElement.webidl b/components/script/dom/webidls/HTMLStyleElement.webidl index dd68cb6270a..0bcb86af24b 100644 --- a/components/script/dom/webidls/HTMLStyleElement.webidl +++ b/components/script/dom/webidls/HTMLStyleElement.webidl @@ -7,6 +7,7 @@ interface HTMLStyleElement : HTMLElement { [HTMLConstructor] constructor(); + attribute boolean disabled; // [CEReactions] // attribute DOMString media; // [CEReactions] diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl index aea9a16e725..b10173b408e 100644 --- a/components/script/dom/webidls/Navigator.webidl +++ b/components/script/dom/webidls/Navigator.webidl @@ -69,7 +69,7 @@ partial interface Navigator { // https://w3c.github.io/gamepad/#navigator-interface-extension partial interface Navigator { - [Pref="dom.gamepad.enabled"] GamepadList getGamepads(); + [Pref="dom.gamepad.enabled"] sequence getGamepads(); }; // https://html.spec.whatwg.org/multipage/#navigatorconcurrenthardware diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs index f96b41e17cc..2a59cbad5c1 100644 --- a/components/script/dom/worklet.rs +++ b/components/script/dom/worklet.rs @@ -291,9 +291,9 @@ impl WorkletThreadPool { primary_sender: primary_sender, hot_backup_sender: hot_backup_sender, cold_backup_sender: cold_backup_sender, - control_sender_0: WorkletThread::spawn(primary_role, init.clone()), - control_sender_1: WorkletThread::spawn(hot_backup_role, init.clone()), - control_sender_2: WorkletThread::spawn(cold_backup_role, init), + control_sender_0: WorkletThread::spawn(primary_role, init.clone(), 0), + control_sender_1: WorkletThread::spawn(hot_backup_role, init.clone(), 1), + control_sender_2: WorkletThread::spawn(cold_backup_role, init, 2), } } @@ -464,32 +464,38 @@ impl WorkletThread { /// Spawn a new worklet thread, returning the channel to send it control messages. #[allow(unsafe_code)] #[allow(crown::unrooted_must_root)] - fn spawn(role: WorkletThreadRole, init: WorkletThreadInit) -> Sender { + fn spawn( + role: WorkletThreadRole, + init: WorkletThreadInit, + thread_index: u8, + ) -> Sender { let (control_sender, control_receiver) = unbounded(); - // TODO: name this thread - thread::spawn(move || { - // TODO: add a new IN_WORKLET thread state? - // TODO: set interrupt handler? - // TODO: configure the JS runtime (e.g. discourage GC, encourage agressive JIT) - debug!("Initializing worklet thread."); - thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); - let roots = RootCollection::new(); - let _stack_roots = ThreadLocalStackRoots::new(&roots); - let mut thread = RootedTraceableBox::new(WorkletThread { - role: role, - control_receiver: control_receiver, - primary_sender: init.primary_sender, - hot_backup_sender: init.hot_backup_sender, - cold_backup_sender: init.cold_backup_sender, - global_init: init.global_init, - global_scopes: HashMap::new(), - control_buffer: None, - runtime: new_rt_and_cx(None), - should_gc: false, - gc_threshold: MIN_GC_THRESHOLD, - }); - thread.run(); - }); + let _ = thread::Builder::new() + .name(format!("Worklet#{thread_index}")) + .spawn(move || { + // TODO: add a new IN_WORKLET thread state? + // TODO: set interrupt handler? + // TODO: configure the JS runtime (e.g. discourage GC, encourage agressive JIT) + debug!("Initializing worklet thread."); + thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); + let roots = RootCollection::new(); + let _stack_roots = ThreadLocalStackRoots::new(&roots); + let mut thread = RootedTraceableBox::new(WorkletThread { + role: role, + control_receiver: control_receiver, + primary_sender: init.primary_sender, + hot_backup_sender: init.hot_backup_sender, + cold_backup_sender: init.cold_backup_sender, + global_init: init.global_init, + global_scopes: HashMap::new(), + control_buffer: None, + runtime: new_rt_and_cx(None), + should_gc: false, + gc_threshold: MIN_GC_THRESHOLD, + }); + thread.run(); + }) + .expect("Couldn't start worklet thread"); control_sender } diff --git a/components/script/layout_dom/node.rs b/components/script/layout_dom/node.rs index 9ce25c78f84..ceacbeb7c88 100644 --- a/components/script/layout_dom/node.rs +++ b/components/script/layout_dom/node.rs @@ -211,7 +211,7 @@ impl<'dom, LayoutDataType: LayoutDataTrait> LayoutNode<'dom> unsafe fn initialize_data(&self) { if self.get_style_and_opaque_layout_data().is_none() { let opaque = StyleAndOpaqueLayoutData::new( - StyleData::new(), + StyleData::default(), AtomicRefCell::new(LayoutDataType::default()), ); self.init_style_and_opaque_layout_data(opaque); diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index e0efe1055f4..c0f3555b1c2 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -21,7 +21,7 @@ media-gstreamer = ["servo-media-gstreamer", "gstreamer"] multiview = ["compositing/multiview", "constellation/multiview"] native-bluetooth = ["bluetooth/native-bluetooth"] no-wgl = ["canvas/no-wgl"] -no_static_freetype = ["webrender/no_static_freetype"] +dynamic_freetype = ["webrender/dynamic_freetype"] profilemozjs = ["script/profilemozjs"] refcell_backtrace = ["script/refcell_backtrace"] webdriver = ["webdriver_server"] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 31afcd930ca..e5ea71fd81d 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -88,7 +88,7 @@ use surfman::{GLApi, GLVersion}; #[cfg(target_os = "linux")] use surfman::{NativeConnection, NativeContext}; use webrender::{RenderApiSender, ShaderPrecacheFlags}; -use webrender_api::{DocumentId, FontInstanceKey, FontKey, ImageKey}; +use webrender_api::{ColorF, DocumentId, FontInstanceKey, FontKey, FramePublishId, ImageKey}; use webrender_traits::{ WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, WebrenderImageHandlerType, }; @@ -205,7 +205,7 @@ impl webrender_api::RenderNotifier for RenderNotifier { _document_id: DocumentId, _scrolled: bool, composite_needed: bool, - _render_time_ns: Option, + _frame_publish_id: FramePublishId, ) { self.compositor_proxy .send(CompositorMsg::NewWebRenderFrameReady(composite_needed)); @@ -310,7 +310,7 @@ where let coordinates: compositing::windowing::EmbedderCoordinates = window.get_coordinates(); let device_pixel_ratio = coordinates.hidpi_factor.get(); - let viewport_size = coordinates.viewport.size.to_f32() / device_pixel_ratio; + let viewport_size = coordinates.viewport.size().to_f32() / device_pixel_ratio; let (mut webrender, webrender_api_sender) = { let mut debug_flags = webrender::DebugFlags::empty(); @@ -320,11 +320,17 @@ where ); let render_notifier = Box::new(RenderNotifier::new(compositor_proxy.clone())); - webrender::Renderer::new( + let clear_color = servo_config::pref!(shell.background_color.rgba); + let clear_color = ColorF::new( + clear_color[0] as f32, + clear_color[1] as f32, + clear_color[2] as f32, + clear_color[3] as f32, + ); + webrender::create_webrender_instance( webrender_gl.clone(), render_notifier, - webrender::RendererOptions { - device_pixel_ratio, + webrender::WebRenderOptions { resource_override_path: opts.shaders_dir.clone(), enable_aa: !opts.debug.disable_text_antialiasing, debug_flags: debug_flags, @@ -336,7 +342,7 @@ where enable_subpixel_aa: pref!(gfx.subpixel_text_antialiasing.enabled) && !opts.debug.disable_subpixel_text_antialiasing, allow_texture_swizzling: pref!(gfx.texture_swizzling.enabled), - clear_color: None, + clear_color, ..Default::default() }, None, @@ -345,7 +351,7 @@ where }; let webrender_api = webrender_api_sender.create_api(); - let webrender_document = webrender_api.add_document(coordinates.get_viewport().size); + let webrender_document = webrender_api.add_document(coordinates.get_viewport().size()); // Important that this call is done in a single-threaded fashion, we // can't defer it after `create_constellation` has started. @@ -387,7 +393,7 @@ where embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone()); } - let wgpu_image_handler = webgpu::WGPUExternalImages::new(); + let wgpu_image_handler = webgpu::WGPUExternalImages::default(); let wgpu_image_map = wgpu_image_handler.images.clone(); external_image_handlers.set_handler( Box::new(wgpu_image_handler), @@ -460,7 +466,6 @@ where webxr_main_thread, }, composite_target, - opts.is_running_problem_test, opts.exit_after_load, opts.debug.convert_mouse_to_touch, top_level_browsing_context_id, @@ -880,7 +885,7 @@ where } pub fn pinch_zoom_level(&self) -> f32 { - self.compositor.pinch_zoom_level() + self.compositor.pinch_zoom_level().get() } pub fn setup_logging(&self) { @@ -1022,7 +1027,6 @@ fn create_constellation( initial_window_size, opts.random_pipeline_closure_probability, opts.random_pipeline_closure_seed, - opts.is_running_problem_test, opts.hard_fail, !opts.debug.disable_canvas_antialiasing, canvas_create_sender, diff --git a/components/shared/bluetooth/scanfilter.rs b/components/shared/bluetooth/scanfilter.rs index b5590e1aa40..659e34bc4dd 100644 --- a/components/shared/bluetooth/scanfilter.rs +++ b/components/shared/bluetooth/scanfilter.rs @@ -49,7 +49,7 @@ impl BluetoothScanfilter { name, name_prefix, services: ServiceUUIDSequence::new(services), - manufacturer_data: manufacturer_data, + manufacturer_data, service_data, } } @@ -124,7 +124,7 @@ impl RequestDeviceoptions { services: ServiceUUIDSequence, ) -> RequestDeviceoptions { RequestDeviceoptions { - filters: filters, + filters, optional_services: services, } } diff --git a/components/shared/canvas/canvas.rs b/components/shared/canvas/canvas.rs index d984dd05ded..f656b5dc92d 100644 --- a/components/shared/canvas/canvas.rs +++ b/components/shared/canvas/canvas.rs @@ -115,11 +115,11 @@ impl LinearGradientStyle { stops: Vec, ) -> LinearGradientStyle { LinearGradientStyle { - x0: x0, - y0: y0, - x1: x1, - y1: y1, - stops: stops, + x0, + y0, + x1, + y1, + stops, } } } @@ -146,13 +146,13 @@ impl RadialGradientStyle { stops: Vec, ) -> RadialGradientStyle { RadialGradientStyle { - x0: x0, - y0: y0, - r0: r0, - x1: x1, - y1: y1, - r1: r1, - stops: stops, + x0, + y0, + r0, + x1, + y1, + r1, + stops, } } } @@ -402,8 +402,9 @@ impl FromStr for CompositionOrBlending { } } -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub enum TextAlign { + #[default] Start, End, Left, @@ -426,17 +427,12 @@ impl FromStr for TextAlign { } } -impl Default for TextAlign { - fn default() -> TextAlign { - TextAlign::Start - } -} - -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub enum TextBaseline { Top, Hanging, Middle, + #[default] Alphabetic, Ideographic, Bottom, @@ -458,16 +454,11 @@ impl FromStr for TextBaseline { } } -impl Default for TextBaseline { - fn default() -> TextBaseline { - TextBaseline::Alphabetic - } -} - -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub enum Direction { Ltr, Rtl, + #[default] Inherit, } @@ -483,9 +474,3 @@ impl FromStr for Direction { } } } - -impl Default for Direction { - fn default() -> Direction { - Direction::Inherit - } -} diff --git a/components/shared/canvas/webgl.rs b/components/shared/canvas/webgl.rs index 820f3bc7925..a3f68563308 100644 --- a/components/shared/canvas/webgl.rs +++ b/components/shared/canvas/webgl.rs @@ -140,10 +140,7 @@ pub struct WebGLMsgSender { impl WebGLMsgSender { pub fn new(id: WebGLContextId, sender: WebGLChan) -> Self { - WebGLMsgSender { - ctx_id: id, - sender: sender, - } + WebGLMsgSender { ctx_id: id, sender } } /// Returns the WebGLContextId associated to this sender @@ -549,6 +546,11 @@ macro_rules! define_resource_id { impl $name { #[allow(unsafe_code)] #[inline] + /// Create a new $name. + /// + /// # Safety + /// + /// Using an invalid OpenGL id may result in undefined behavior. pub unsafe fn new(id: $type) -> Self { $name(::new_unchecked(id)) } @@ -922,7 +924,7 @@ mod gl_ext_constants { pub const COMPRESSED_RGBA_S3TC_DXT5_EXT: GLenum = 0x83F3; pub const COMPRESSED_RGB_ETC1_WEBGL: GLenum = 0x8D64; - pub static COMPRESSIONS: &'static [GLenum] = &[ + pub static COMPRESSIONS: &[GLenum] = &[ COMPRESSED_RGB_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT3_EXT, @@ -1061,18 +1063,18 @@ impl TexFormat { /// Returns whether this format is a known sized or unsized format. pub fn is_sized(&self) -> bool { - match self { + !matches!( + self, TexFormat::DepthComponent | - TexFormat::DepthStencil | - TexFormat::Alpha | - TexFormat::Red | - TexFormat::RG | - TexFormat::RGB | - TexFormat::RGBA | - TexFormat::Luminance | - TexFormat::LuminanceAlpha => false, - _ => true, - } + TexFormat::DepthStencil | + TexFormat::Alpha | + TexFormat::Red | + TexFormat::RG | + TexFormat::RGB | + TexFormat::RGBA | + TexFormat::Luminance | + TexFormat::LuminanceAlpha + ) } pub fn to_unsized(self) -> TexFormat { diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 4271caa90d9..0c26727c898 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -178,7 +178,7 @@ pub enum EmbedderMsg { SetCursor(Cursor), /// A favicon was detected NewFavicon(ServoUrl), - /// tag finished parsing + /// `` tag finished parsing HeadParsed, /// The history state has changed. HistoryChanged(Vec, usize), diff --git a/components/shared/gfx/lib.rs b/components/shared/gfx/lib.rs index 7cac7ef1fb1..e3749b37e03 100644 --- a/components/shared/gfx/lib.rs +++ b/components/shared/gfx/lib.rs @@ -25,9 +25,9 @@ impl Epoch { } } -impl Into for Epoch { - fn into(self) -> WebRenderEpoch { - WebRenderEpoch(self.0) +impl From for WebRenderEpoch { + fn from(val: Epoch) -> Self { + WebRenderEpoch(val.0) } } @@ -114,7 +114,7 @@ pub fn combine_id_with_fragment_type(id: usize, fragment_type: FragmentType) -> pub fn node_id_from_scroll_id(id: usize) -> Option { if (id & !SPECIAL_SCROLL_ROOT_ID_MASK) != 0 { - return Some((id & !3) as usize); + return Some(id & !3); } None } diff --git a/components/shared/gfx/print_tree.rs b/components/shared/gfx/print_tree.rs index 60201733c66..03e47b21317 100644 --- a/components/shared/gfx/print_tree.rs +++ b/components/shared/gfx/print_tree.rs @@ -28,17 +28,17 @@ impl PrintTree { self.print_level_prefix(); - let items: Vec<&str> = queued_title.split("\n").collect(); + let items: Vec<&str> = queued_title.split('\n').collect(); println!("\u{251C}\u{2500} {}", items[0]); for i in 1..items.len() { self.print_level_child_indentation(); print!("{}", items[i]); if i < items.len() { - print!("\n"); + println!(); } } - self.level = self.level + 1; + self.level += 1; } /// Ascend one level in the tree. @@ -69,13 +69,13 @@ impl PrintTree { fn flush_queued_item(&mut self, prefix: &str) { if let Some(queued_item) = self.queued_item.take() { self.print_level_prefix(); - let items: Vec<&str> = queued_item.split("\n").collect(); + let items: Vec<&str> = queued_item.split('\n').collect(); println!("{} {}", prefix, items[0]); for i in 1..items.len() { self.print_level_child_indentation(); print!("{}", items[i]); if i < items.len() { - print!("\n"); + println!(); } } } diff --git a/components/shared/msg/constellation_msg.rs b/components/shared/msg/constellation_msg.rs index 45f43b612b7..44f3eb6b12e 100644 --- a/components/shared/msg/constellation_msg.rs +++ b/components/shared/msg/constellation_msg.rs @@ -5,6 +5,8 @@ //! The high-level interface from script to constellation. Using this abstract interface helps //! reduce coupling between these two components. +#![allow(clippy::new_without_default)] + use std::cell::Cell; use std::num::NonZeroU32; use std::sync::Arc; @@ -80,17 +82,19 @@ pub struct PipelineNamespaceInstaller { namespace_receiver: IpcReceiver, } -impl PipelineNamespaceInstaller { - pub fn new() -> Self { +impl Default for PipelineNamespaceInstaller { + fn default() -> Self { let (namespace_sender, namespace_receiver) = ipc::channel().expect("PipelineNamespaceInstaller ipc channel failure"); - PipelineNamespaceInstaller { + Self { request_sender: None, - namespace_sender: namespace_sender, - namespace_receiver: namespace_receiver, + namespace_sender, + namespace_receiver, } } +} +impl PipelineNamespaceInstaller { /// Provide a request sender to send requests to the constellation. pub fn set_sender(&mut self, sender: IpcSender) { self.request_sender = Some(sender); @@ -121,7 +125,7 @@ lazy_static! { /// /// Use PipelineNamespace::fetch_install to install a unique pipeline-namespace from the calling thread. static ref PIPELINE_NAMESPACE_INSTALLER: Arc> = - Arc::new(Mutex::new(PipelineNamespaceInstaller::new())); + Arc::new(Mutex::new(PipelineNamespaceInstaller::default())); } /// Each pipeline ID needs to be unique. However, it also needs to be possible to @@ -247,7 +251,7 @@ size_of_test!(BrowsingContextId, 8); size_of_test!(Option, 8); impl BrowsingContextId { - pub fn new() -> BrowsingContextId { + pub fn new() -> Self { PIPELINE_NAMESPACE.with(|tls| { let mut namespace = tls.get().expect("No namespace set for this thread!"); let new_browsing_context_id = namespace.next_browsing_context_id(); @@ -292,6 +296,7 @@ impl TopLevelBrowsingContextId { pub fn new() -> TopLevelBrowsingContextId { TopLevelBrowsingContextId(BrowsingContextId::new()) } + /// Each script and layout thread should have the top-level browsing context id installed, /// since it is used by crash reporting. pub fn install(id: TopLevelBrowsingContextId) { @@ -544,7 +549,7 @@ impl fmt::Debug for HangAlert { "\n The following component is experiencing a transient hang: \n {:?}", component_id )?; - (annotation.clone(), None) + (*annotation, None) }, HangAlert::Permanent(component_id, annotation, profile) => { write!( @@ -552,7 +557,7 @@ impl fmt::Debug for HangAlert { "\n The following component is experiencing a permanent hang: \n {:?}", component_id )?; - (annotation.clone(), profile.clone()) + (*annotation, profile.clone()) }, }; diff --git a/components/shared/net/blob_url_store.rs b/components/shared/net/blob_url_store.rs index ab853b702c9..5e487b8038d 100644 --- a/components/shared/net/blob_url_store.rs +++ b/components/shared/net/blob_url_store.rs @@ -41,20 +41,24 @@ pub struct BlobBuf { /// Parse URL as Blob URL scheme's definition /// /// -pub fn parse_blob_url(url: &ServoUrl) -> Result<(Uuid, FileOrigin), ()> { - let url_inner = Url::parse(url.path()).map_err(|_| ())?; +pub fn parse_blob_url(url: &ServoUrl) -> Result<(Uuid, FileOrigin), &'static str> { + let url_inner = Url::parse(url.path()).map_err(|_| "Failed to parse URL path")?; let segs = url_inner .path_segments() .map(|c| c.collect::>()) - .ok_or(())?; + .ok_or("URL has no path segments")?; - if url.query().is_some() || segs.len() > 1 { - return Err(()); + if url.query().is_some() { + return Err("URL should not contain a query"); + } + + if segs.len() > 1 { + return Err("URL should not have more than one path segment"); } let id = { - let id = segs.first().ok_or(())?; - Uuid::from_str(id).map_err(|_| ())? + let id = segs.first().ok_or("URL has no path segments")?; + Uuid::from_str(id).map_err(|_| "Failed to parse UUID from path segment")? }; Ok((id, get_blob_origin(&ServoUrl::from_url(url_inner)))) } diff --git a/components/shared/net/fetch/headers.rs b/components/shared/net/fetch/headers.rs index ae95066bcf5..14caf03eea8 100644 --- a/components/shared/net/fetch/headers.rs +++ b/components/shared/net/fetch/headers.rs @@ -14,5 +14,5 @@ pub fn get_value_from_header_list(name: &str, headers: &HeaderMap) -> Option>().join(&[0x2C, 0x20][..])); + Some(values.collect::>().join(&[0x2C, 0x20][..])) } diff --git a/components/shared/net/image/base.rs b/components/shared/net/image/base.rs index 74e2d8823dc..66257012df2 100644 --- a/components/shared/net/image/base.rs +++ b/components/shared/net/image/base.rs @@ -59,12 +59,12 @@ pub fn load_from_memory(buffer: &[u8], cors_status: CorsStatus) -> Option Ok(_) => match image::load_from_memory(buffer) { Ok(image) => { let mut rgba = image.into_rgba8(); - pixels::rgba8_byte_swap_colors_inplace(&mut *rgba); + pixels::rgba8_byte_swap_colors_inplace(&mut rgba); Some(Image { width: rgba.width(), height: rgba.height(), format: PixelFormat::BGRA8, - bytes: IpcSharedMemory::from_bytes(&*rgba), + bytes: IpcSharedMemory::from_bytes(&rgba), id: None, cors_status, }) diff --git a/components/shared/net/image_cache.rs b/components/shared/net/image_cache.rs index 81d34964db4..d1087bace63 100644 --- a/components/shared/net/image_cache.rs +++ b/components/shared/net/image_cache.rs @@ -42,10 +42,7 @@ pub struct ImageResponder { impl ImageResponder { pub fn new(sender: IpcSender, id: PendingImageId) -> ImageResponder { - ImageResponder { - sender: sender, - id: id, - } + ImageResponder { sender, id } } pub fn respond(&self, response: ImageResponse) { @@ -54,7 +51,7 @@ impl ImageResponder { // That's not a case that's worth warning about. // TODO(#15501): are there cases in which we should perform cleanup? let _ = self.sender.send(PendingImageResponse { - response: response, + response, id: self.id, }); } diff --git a/components/shared/net/lib.rs b/components/shared/net/lib.rs index e69bd4a317b..95f8856689d 100644 --- a/components/shared/net/lib.rs +++ b/components/shared/net/lib.rs @@ -94,9 +94,9 @@ impl CustomResponse { body: Vec, ) -> CustomResponse { CustomResponse { - headers: headers, - raw_status: raw_status, - body: body, + headers, + raw_status, + body, } } } @@ -567,7 +567,7 @@ pub enum ResourceTimingType { impl ResourceFetchTiming { pub fn new(timing_type: ResourceTimingType) -> ResourceFetchTiming { ResourceFetchTiming { - timing_type: timing_type, + timing_type, timing_check_passed: true, domain_lookup_start: 0, redirect_count: 0, @@ -587,12 +587,12 @@ impl ResourceFetchTiming { // TODO currently this is being set with precise time ns when it should be time since // time origin (as described in Performance::now) pub fn set_attribute(&mut self, attribute: ResourceAttribute) { - let should_attribute_always_be_updated = match attribute { + let should_attribute_always_be_updated = matches!( + attribute, ResourceAttribute::FetchStart | - ResourceAttribute::ResponseEnd | - ResourceAttribute::StartTime(_) => true, - _ => false, - }; + ResourceAttribute::ResponseEnd | + ResourceAttribute::StartTime(_) + ); if !self.timing_check_passed && !should_attribute_always_be_updated { return; } @@ -782,7 +782,7 @@ impl NetworkError { /// Normalize `slice`, as defined by /// [the Fetch Spec](https://fetch.spec.whatwg.org/#concept-header-value-normalize). pub fn trim_http_whitespace(mut slice: &[u8]) -> &[u8] { - const HTTP_WS_BYTES: &'static [u8] = b"\x09\x0A\x0D\x20"; + const HTTP_WS_BYTES: &[u8] = b"\x09\x0A\x0D\x20"; loop { match slice.split_first() { diff --git a/components/shared/net/pub_domains.rs b/components/shared/net/pub_domains.rs index 1efb8faf56d..ca56a6f0bbb 100644 --- a/components/shared/net/pub_domains.rs +++ b/components/shared/net/pub_domains.rs @@ -21,7 +21,7 @@ use embedder_traits::resources::{self, Resource}; use lazy_static::lazy_static; use servo_url::{Host, ImmutableOrigin, ServoUrl}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct PubDomainRules { rules: HashSet, wildcards: HashSet, @@ -37,12 +37,12 @@ impl<'a> FromIterator<&'a str> for PubDomainRules { where T: IntoIterator, { - let mut result = PubDomainRules::new(); + let mut result = PubDomainRules::default(); for item in iter { - if item.starts_with("!") { - result.exceptions.insert(String::from(&item[1..])); - } else if item.starts_with("*.") { - result.wildcards.insert(String::from(&item[2..])); + if let Some(stripped) = item.strip_prefix('!') { + result.exceptions.insert(String::from(stripped)); + } else if let Some(stripped) = item.strip_prefix("*.") { + result.wildcards.insert(String::from(stripped)); } else { result.rules.insert(String::from(item)); } @@ -52,13 +52,6 @@ impl<'a> FromIterator<&'a str> for PubDomainRules { } impl PubDomainRules { - pub fn new() -> PubDomainRules { - PubDomainRules { - rules: HashSet::new(), - wildcards: HashSet::new(), - exceptions: HashSet::new(), - } - } pub fn parse(content: &str) -> PubDomainRules { content .lines() @@ -68,23 +61,21 @@ impl PubDomainRules { .collect() } fn suffix_pair<'a>(&self, domain: &'a str) -> (&'a str, &'a str) { - let domain = domain.trim_start_matches("."); + let domain = domain.trim_start_matches('.'); let mut suffix = domain; let mut prev_suffix = domain; - for (index, _) in domain.match_indices(".") { + for (index, _) in domain.match_indices('.') { let next_suffix = &domain[index + 1..]; if self.exceptions.contains(suffix) { return (next_suffix, suffix); - } else if self.wildcards.contains(next_suffix) { - return (suffix, prev_suffix); - } else if self.rules.contains(suffix) { - return (suffix, prev_suffix); - } else { - prev_suffix = suffix; - suffix = next_suffix; } + if self.wildcards.contains(next_suffix) || self.rules.contains(suffix) { + return (suffix, prev_suffix); + } + prev_suffix = suffix; + suffix = next_suffix; } - return (suffix, prev_suffix); + (suffix, prev_suffix) } pub fn public_suffix<'a>(&self, domain: &'a str) -> &'a str { let (public, _) = self.suffix_pair(domain); @@ -98,8 +89,8 @@ impl PubDomainRules { // Speeded-up version of // domain != "" && // self.public_suffix(domain) == domain. - let domain = domain.trim_start_matches("."); - match domain.find(".") { + let domain = domain.trim_start_matches('.'); + match domain.find('.') { None => !domain.is_empty(), Some(index) => { !self.exceptions.contains(domain) && self.wildcards.contains(&domain[index + 1..]) || @@ -111,8 +102,8 @@ impl PubDomainRules { // Speeded-up version of // self.public_suffix(domain) != domain && // self.registrable_suffix(domain) == domain. - let domain = domain.trim_start_matches("."); - match domain.find(".") { + let domain = domain.trim_start_matches('.'); + match domain.find('.') { None => false, Some(index) => { self.exceptions.contains(domain) || @@ -151,7 +142,7 @@ pub fn is_reg_domain(domain: &str) -> bool { pub fn reg_host(url: &ServoUrl) -> Option { match url.origin() { ImmutableOrigin::Tuple(_, Host::Domain(domain), _) => { - Some(Host::Domain(String::from(reg_suffix(&*domain)))) + Some(Host::Domain(String::from(reg_suffix(&domain)))) }, ImmutableOrigin::Tuple(_, ip, _) => Some(ip), ImmutableOrigin::Opaque(_) => None, diff --git a/components/shared/net/request.rs b/components/shared/net/request.rs index 1f9f0abf986..346614bc73e 100644 --- a/components/shared/net/request.rs +++ b/components/shared/net/request.rs @@ -186,7 +186,7 @@ impl RequestBody { } } - /// Step 12 of https://fetch.spec.whatwg.org/#concept-http-redirect-fetch + /// Step 12 of pub fn extract_source(&mut self) { match self.source { BodySource::Null => panic!("Null sources should never be re-directed."), @@ -207,8 +207,9 @@ impl RequestBody { self.source == BodySource::Null } + #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> Option { - self.total_bytes.clone() + self.total_bytes } } @@ -264,7 +265,7 @@ impl RequestBuilder { pub fn new(url: ServoUrl, referrer: Referrer) -> RequestBuilder { RequestBuilder { method: Method::GET, - url: url, + url, headers: HeaderMap::new(), unsafe_request: false, body: None, @@ -277,7 +278,7 @@ impl RequestBuilder { credentials_mode: CredentialsMode::CredentialsSameOrigin, use_url_credentials: false, origin: ImmutableOrigin::new_opaque(), - referrer: referrer, + referrer, referrer_policy: None, pipeline_id: None, redirect_mode: RedirectMode::Follow, @@ -524,9 +525,9 @@ impl Request { initiator: Initiator::None, destination: Destination::None, origin: origin.unwrap_or(Origin::Client), - referrer: referrer, + referrer, referrer_policy: None, - pipeline_id: pipeline_id, + pipeline_id, synchronous: false, mode: RequestMode::NoCors, use_cors_preflight: false, @@ -540,7 +541,7 @@ impl Request { redirect_count: 0, response_tainting: ResponseTainting::Basic, csp_list: None, - https_state: https_state, + https_state, crash: None, } } @@ -567,19 +568,19 @@ impl Request { /// pub fn is_subresource_request(&self) -> bool { - match self.destination { + matches!( + self.destination, Destination::Audio | - Destination::Font | - Destination::Image | - Destination::Manifest | - Destination::Script | - Destination::Style | - Destination::Track | - Destination::Video | - Destination::Xslt | - Destination::None => true, - _ => false, - } + Destination::Font | + Destination::Image | + Destination::Manifest | + Destination::Script | + Destination::Style | + Destination::Track | + Destination::Video | + Destination::Xslt | + Destination::None + ) } pub fn timing_type(&self) -> ResourceTimingType { @@ -605,7 +606,7 @@ impl Referrer { // TODO: values in the control-code range are being quietly stripped out by // HeaderMap and never reach this function to be loudly rejected! fn is_cors_unsafe_request_header_byte(value: &u8) -> bool { - match value { + matches!(value, 0x00..=0x08 | 0x10..=0x19 | 0x22 | @@ -621,9 +622,8 @@ fn is_cors_unsafe_request_header_byte(value: &u8) -> bool { 0x5D | 0x7B | 0x7D | - 0x7F => true, - _ => false, - } + 0x7F + ) } // https://fetch.spec.whatwg.org/#cors-safelisted-request-header @@ -635,18 +635,19 @@ fn is_cors_safelisted_request_accept(value: &[u8]) -> bool { // https://fetch.spec.whatwg.org/#cors-safelisted-request-header // subclauses `accept-language`, `content-language` fn is_cors_safelisted_language(value: &[u8]) -> bool { - value.iter().all(|&x| match x { - 0x30..=0x39 | - 0x41..=0x5A | - 0x61..=0x7A | - 0x20 | - 0x2A | - 0x2C | - 0x2D | - 0x2E | - 0x3B | - 0x3D => true, - _ => false, + value.iter().all(|&x| { + matches!(x, + 0x30..=0x39 | + 0x41..=0x5A | + 0x61..=0x7A | + 0x20 | + 0x2A | + 0x2C | + 0x2D | + 0x2E | + 0x3B | + 0x3D + ) }) } @@ -697,10 +698,7 @@ pub fn is_cors_safelisted_request_header, V: AsRef<[u8]>>( /// pub fn is_cors_safelisted_method(m: &Method) -> bool { - match *m { - Method::GET | Method::HEAD | Method::POST => true, - _ => false, - } + matches!(*m, Method::GET | Method::HEAD | Method::POST) } /// @@ -733,7 +731,7 @@ pub fn get_cors_unsafe_header_names(headers: &HeaderMap) -> Vec { } // Step 6 - return convert_header_names_to_sorted_lowercase_set(unsafe_names); + convert_header_names_to_sorted_lowercase_set(unsafe_names) } /// @@ -745,5 +743,5 @@ pub fn convert_header_names_to_sorted_lowercase_set( let mut ordered_set = header_names.to_vec(); ordered_set.sort_by(|a, b| a.as_str().partial_cmp(b.as_str()).unwrap()); ordered_set.dedup(); - return ordered_set.into_iter().cloned().collect(); + ordered_set.into_iter().cloned().collect() } diff --git a/components/shared/net/response.rs b/components/shared/net/response.rs index 15b8e53aa8b..cbdbd2342c5 100644 --- a/components/shared/net/response.rs +++ b/components/shared/net/response.rs @@ -189,10 +189,7 @@ impl Response { } pub fn is_network_error(&self) -> bool { - match self.response_type { - ResponseType::Error(..) => true, - _ => false, - } + matches!(self.response_type, ResponseType::Error(..)) } pub fn get_network_error(&self) -> Option<&NetworkError> { @@ -204,7 +201,7 @@ impl Response { pub fn actual_response(&self) -> &Response { if self.return_internal && self.internal_response.is_some() { - &**self.internal_response.as_ref().unwrap() + self.internal_response.as_ref().unwrap() } else { self } @@ -212,7 +209,7 @@ impl Response { pub fn actual_response_mut(&mut self) -> &mut Response { if self.return_internal && self.internal_response.is_some() { - &mut **self.internal_response.as_mut().unwrap() + self.internal_response.as_mut().unwrap() } else { self } @@ -258,10 +255,7 @@ impl Response { ResponseType::Basic => { let headers = old_headers.iter().filter(|(name, _)| { - match &*name.as_str().to_ascii_lowercase() { - "set-cookie" | "set-cookie2" => false, - _ => true - } + !matches!(&*name.as_str().to_ascii_lowercase(), "set-cookie" | "set-cookie2") }).map(|(n, v)| (n.clone(), v.clone())).collect(); response.headers = headers; }, @@ -315,7 +309,7 @@ impl Response { metadata.status = response.raw_status.clone(); metadata.https_state = response.https_state; metadata.referrer = response.referrer.clone(); - metadata.referrer_policy = response.referrer_policy.clone(); + metadata.referrer_policy = response.referrer_policy; metadata.redirected = response.actual_response().url_list.len() > 1; metadata } diff --git a/components/shared/script/compositor.rs b/components/shared/script/compositor.rs index c09b2edb0e3..e66c3bf8227 100644 --- a/components/shared/script/compositor.rs +++ b/components/shared/script/compositor.rs @@ -7,9 +7,17 @@ use embedder_traits::Cursor; use serde::{Deserialize, Serialize}; use webrender_api::units::{LayoutSize, LayoutVector2D}; -use webrender_api::{ - Epoch, ExternalScrollId, PipelineId, ScrollLocation, ScrollSensitivity, SpatialId, -}; +use webrender_api::{Epoch, ExternalScrollId, PipelineId, ScrollLocation, SpatialId}; + +/// The scroll sensitivity of a scroll node ie whether it can be scrolled due to input event and +/// script events or only script events. +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum ScrollSensitivity { + /// This node can be scrolled by input and script events. + ScriptAndInputEvents, + /// This node can only be scrolled by script events. + Script, +} /// Information that Servo keeps alongside WebRender display items /// in order to add more context to hit test results. @@ -131,7 +139,7 @@ impl ScrollTreeNode { let scrollable_width = info.scrollable_size.width; let scrollable_height = info.scrollable_size.height; - let original_layer_scroll_offset = info.offset.clone(); + let original_layer_scroll_offset = info.offset; if scrollable_width > 0. { info.offset.x = (info.offset.x + delta.x).min(0.0).max(-scrollable_width); @@ -172,10 +180,10 @@ impl ScrollTree { parent: parent.cloned(), scroll_info, }); - return ScrollTreeNodeId { + ScrollTreeNodeId { index: self.nodes.len() - 1, spatial_id, - }; + } } /// Get a mutable reference to the node with the given index. @@ -198,7 +206,7 @@ impl ScrollTree { scroll_location: ScrollLocation, ) -> Option<(ExternalScrollId, LayoutVector2D)> { let parent = { - let ref mut node = self.get_node_mut(scroll_node_id); + let node = &mut self.get_node_mut(scroll_node_id); let result = node.scroll(scroll_location); if result.is_some() { return result; @@ -208,6 +216,25 @@ impl ScrollTree { parent.and_then(|parent| self.scroll_node_or_ancestor(&parent, scroll_location)) } + + /// Given an [`ExternalScrollId`] and an offset, update the scroll offset of the scroll node + /// with the given id. + pub fn set_scroll_offsets_for_node_with_external_scroll_id( + &mut self, + external_scroll_id: ExternalScrollId, + offset: LayoutVector2D, + ) -> bool { + for node in self.nodes.iter_mut() { + match node.scroll_info { + Some(ref mut scroll_info) if scroll_info.external_id == external_scroll_id => { + scroll_info.offset = offset; + return true; + }, + _ => {}, + } + } + false + } } /// A data structure which stores compositor-side information about @@ -252,6 +279,7 @@ impl CompositorDisplayListInfo { content_size: LayoutSize, pipeline_id: PipelineId, epoch: Epoch, + root_scroll_sensitivity: ScrollSensitivity, ) -> Self { let mut scroll_tree = ScrollTree::default(); let root_reference_frame_id = scroll_tree.add_scroll_tree_node( @@ -265,7 +293,7 @@ impl CompositorDisplayListInfo { Some(ScrollableNodeInfo { external_id: ExternalScrollId(0, pipeline_id), scrollable_size: content_size - viewport_size, - scroll_sensitivity: ScrollSensitivity::ScriptAndInputEvents, + scroll_sensitivity: root_scroll_sensitivity, offset: LayoutVector2D::zero(), }), ); diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index f39089cf3a0..788db0366e0 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -56,7 +56,7 @@ use servo_atoms::Atom; use servo_url::{ImmutableOrigin, ServoUrl}; use style_traits::{CSSPixel, SpeculativePainter}; use webgpu::identity::WebGPUMsg; -use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel, LayoutPoint, WorldPoint}; +use webrender_api::units::{DeviceIntSize, DevicePixel, DevicePoint, LayoutPixel, LayoutPoint}; use webrender_api::{ BuiltDisplayList, BuiltDisplayListDescriptor, DocumentId, ExternalImageData, ExternalScrollId, HitTestFlags, ImageData, ImageDescriptor, ImageKey, PipelineId as WebRenderPipelineId, @@ -194,14 +194,14 @@ impl LoadData { ) -> LoadData { LoadData { load_origin, - url: url, - creator_pipeline_id: creator_pipeline_id, + url, + creator_pipeline_id, method: Method::GET, headers: HeaderMap::new(), data: None, js_eval_result: None, - referrer: referrer, - referrer_policy: referrer_policy, + referrer, + referrer_policy, srcdoc: "".to_string(), inherited_secure_context, crash: None, @@ -977,7 +977,7 @@ impl StructuredSerializedData { // Note: we insert the blob at the original id, // otherwise this will not match the storage key as serialized by SM in `serialized`. // The clone has it's own new Id however. - blob_clones.insert(original_id.clone(), blob_clone); + blob_clones.insert(*original_id, blob_clone); } else { // Not panicking only because this is called from the constellation. warn!("Serialized blob not in memory format(should never happen)."); @@ -1121,7 +1121,7 @@ pub enum ScriptToCompositorMsg { /// Inform WebRender of the existence of this pipeline. SendInitialTransaction(WebRenderPipelineId), /// Perform a scroll operation. - SendScrollNode(LayoutPoint, ExternalScrollId), + SendScrollNode(WebRenderPipelineId, LayoutPoint, ExternalScrollId), /// Inform WebRender of a new display list for the given pipeline. SendDisplayList { /// The [CompositorDisplayListInfo] that describes the display list being sent. @@ -1135,7 +1135,7 @@ pub enum ScriptToCompositorMsg { /// the provided channel sender. HitTest( Option, - WorldPoint, + DevicePoint, HitTestFlags, IpcSender>, ), @@ -1167,11 +1167,17 @@ impl WebrenderIpcSender { } /// Perform a scroll operation. - pub fn send_scroll_node(&self, point: LayoutPoint, scroll_id: ExternalScrollId) { - if let Err(e) = self - .0 - .send(ScriptToCompositorMsg::SendScrollNode(point, scroll_id)) - { + pub fn send_scroll_node( + &self, + pipeline_id: WebRenderPipelineId, + point: LayoutPoint, + scroll_id: ExternalScrollId, + ) { + if let Err(e) = self.0.send(ScriptToCompositorMsg::SendScrollNode( + pipeline_id, + point, + scroll_id, + )) { warn!("Error sending scroll node: {}", e); } } @@ -1192,8 +1198,14 @@ impl WebrenderIpcSender { warn!("Error sending display list: {}", e); } - if let Err(e) = display_list_sender.send(&display_list_data) { - warn!("Error sending display data: {}", e); + if let Err(error) = display_list_sender.send(&display_list_data.items_data) { + warn!("Error sending display list items: {}", error); + } + if let Err(error) = display_list_sender.send(&display_list_data.cache_data) { + warn!("Error sending display list cache data: {}", error); + } + if let Err(error) = display_list_sender.send(&display_list_data.spatial_tree) { + warn!("Error sending display spatial tree: {}", error); } } @@ -1202,7 +1214,7 @@ impl WebrenderIpcSender { pub fn hit_test( &self, pipeline: Option, - point: WorldPoint, + point: DevicePoint, flags: HitTestFlags, ) -> Vec { let (sender, receiver) = ipc::channel().unwrap(); @@ -1263,7 +1275,7 @@ impl WebrenderIpcSender { } senders.into_iter().for_each(|(tx, data)| { - if let Err(e) = tx.send(&*data) { + if let Err(e) = tx.send(&data) { warn!("error sending image data: {}", e); } }); @@ -1308,8 +1320,8 @@ impl SerializedImageData { /// Convert to ``ImageData`. pub fn to_image_data(&self) -> Result { match self { - SerializedImageData::Raw(rx) => rx.recv().map(|data| ImageData::new(data)), - SerializedImageData::External(image) => Ok(ImageData::External(image.clone())), + SerializedImageData::Raw(rx) => rx.recv().map(ImageData::new), + SerializedImageData::External(image) => Ok(ImageData::External(*image)), } } } @@ -1350,6 +1362,6 @@ pub enum GamepadUpdateType { /// Axis(usize, f64), /// Button index and input value - /// Button(usize, f64), } diff --git a/components/shared/script/script_msg.rs b/components/shared/script/script_msg.rs index 8f55db70a12..cc569653dcd 100644 --- a/components/shared/script/script_msg.rs +++ b/components/shared/script/script_msg.rs @@ -402,6 +402,7 @@ pub enum JobError { } #[derive(Debug, Deserialize, Serialize)] +#[allow(clippy::large_enum_variant)] /// Messages sent from Job algorithms steps running in the SW manager, /// in order to resolve or reject the job promise. pub enum JobResult { diff --git a/components/shared/script/serializable.rs b/components/shared/script/serializable.rs index f580a7a824b..d186cad621a 100644 --- a/components/shared/script/serializable.rs +++ b/components/shared/script/serializable.rs @@ -41,7 +41,7 @@ impl FileBlob { /// Get the size of the file. pub fn get_size(&self) -> u64 { - self.size.clone() + self.size } /// Get the cached file data, if any. @@ -56,7 +56,7 @@ impl FileBlob { /// Get the file id. pub fn get_id(&self) -> Uuid { - self.id.clone() + self.id } } @@ -107,7 +107,7 @@ impl BlobImpl { id: file_id, name: Some(name), cache: RefCell::new(None), - size: size, + size, }); BlobImpl { blob_id, @@ -131,7 +131,7 @@ impl BlobImpl { /// Get a clone of the blob-id pub fn blob_id(&self) -> BlobId { - self.blob_id.clone() + self.blob_id } /// Get a clone of the type-string diff --git a/components/shared/script/tests/compositor.rs b/components/shared/script/tests/compositor.rs index d741d7a9d53..289f4ffebf1 100644 --- a/components/shared/script/tests/compositor.rs +++ b/components/shared/script/tests/compositor.rs @@ -3,9 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use euclid::Size2D; -use script_traits::compositor::{ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo}; +use script_traits::compositor::{ + ScrollSensitivity, ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo, +}; use webrender_api::units::LayoutVector2D; -use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, ScrollSensitivity, SpatialId}; +use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, SpatialId}; fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId { let pipeline_id = PipelineId(0, 0); diff --git a/components/shared/script/transferable.rs b/components/shared/script/transferable.rs index 1b579899b61..2daf4a8d3fd 100644 --- a/components/shared/script/transferable.rs +++ b/components/shared/script/transferable.rs @@ -63,7 +63,7 @@ impl MessagePortImpl { /// Maybe get the Id of the entangled port. pub fn entangled_port_id(&self) -> Option { - self.entangled_port.clone() + self.entangled_port } /// Entanged this port with another. @@ -73,10 +73,7 @@ impl MessagePortImpl { /// Is this port enabled? pub fn enabled(&self) -> bool { - match self.state { - MessagePortState::Enabled(_) => true, - _ => false, - } + matches!(self.state, MessagePortState::Enabled(_)) } /// Mark this port as having been shipped. diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 933484fc1fa..84e32a66d92 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -49,11 +49,11 @@ pub struct StyleData { pub parallel: DomParallelInfo, } -impl StyleData { - pub fn new() -> Self { +impl Default for StyleData { + fn default() -> Self { Self { element_data: AtomicRefCell::new(ElementData::default()), - parallel: DomParallelInfo::new(), + parallel: DomParallelInfo::default(), } } } @@ -86,20 +86,12 @@ impl StyleAndOpaqueLayoutData { } /// Information that we need stored in each DOM node. -#[derive(MallocSizeOf)] +#[derive(Default, MallocSizeOf)] pub struct DomParallelInfo { /// The number of children remaining to process during bottom-up traversal. pub children_to_process: AtomicIsize, } -impl DomParallelInfo { - pub fn new() -> DomParallelInfo { - DomParallelInfo { - children_to_process: AtomicIsize::new(0), - } - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum LayoutNodeType { Element(LayoutElementType), diff --git a/components/shared/script_layout/message.rs b/components/shared/script_layout/message.rs index d07272821b0..1409f157666 100644 --- a/components/shared/script_layout/message.rs +++ b/components/shared/script_layout/message.rs @@ -199,11 +199,11 @@ pub struct PendingRestyle { pub damage: RestyleDamage, } -impl PendingRestyle { +impl Default for PendingRestyle { /// Creates a new empty pending restyle. #[inline] - pub fn new() -> Self { - PendingRestyle { + fn default() -> Self { + Self { snapshot: None, hint: RestyleHint::empty(), damage: RestyleDamage::empty(), diff --git a/components/shared/script_layout/wrapper_traits.rs b/components/shared/script_layout/wrapper_traits.rs index 3274bdb641e..2450159c6a4 100644 --- a/components/shared/script_layout/wrapper_traits.rs +++ b/components/shared/script_layout/wrapper_traits.rs @@ -50,17 +50,11 @@ impl PseudoElementType { } pub fn is_before(&self) -> bool { - match *self { - PseudoElementType::Before => true, - _ => false, - } + matches!(*self, PseudoElementType::Before) } pub fn is_replaced_content(&self) -> bool { - match *self { - PseudoElementType::Before | PseudoElementType::After => true, - _ => false, - } + matches!(*self, PseudoElementType::Before | PseudoElementType::After) } pub fn style_pseudo_element(&self) -> PseudoElement { @@ -138,9 +132,8 @@ where ConcreteNode: LayoutNode<'dom>, { fn new(root: ConcreteNode) -> TreeIterator { - let mut stack = vec![]; - stack.push(root); - TreeIterator { stack: stack } + let stack = vec![root]; + TreeIterator { stack } } pub fn next_skipping_children(&mut self) -> Option { @@ -155,7 +148,9 @@ where type Item = ConcreteNode; fn next(&mut self) -> Option { let ret = self.stack.pop(); - ret.map(|node| self.stack.extend(node.rev_children())); + if let Some(node) = ret { + self.stack.extend(node.rev_children()) + } ret } } diff --git a/components/shared/webrender/lib.rs b/components/shared/webrender/lib.rs index 8e48d94e439..a71f9f67760 100644 --- a/components/shared/webrender/lib.rs +++ b/components/shared/webrender/lib.rs @@ -9,9 +9,7 @@ use std::sync::{Arc, Mutex}; use euclid::default::Size2D; use webrender_api::units::TexelRect; -use webrender_api::{ - ExternalImage, ExternalImageHandler, ExternalImageId, ExternalImageSource, ImageRendering, -}; +use webrender_api::{ExternalImage, ExternalImageHandler, ExternalImageId, ExternalImageSource}; /// This trait is used as a bridge between the different GL clients /// in Servo that handles WebRender ExternalImages and the WebRender @@ -39,6 +37,7 @@ pub enum WebrenderImageHandlerType { /// List of Webrender external images to be shared among all external image /// consumers (WebGL, Media, WebGPU). /// It ensures that external image identifiers are unique. +#[derive(Default)] pub struct WebrenderExternalImageRegistry { /// Map of all generated external images. external_images: HashMap, @@ -47,13 +46,6 @@ pub struct WebrenderExternalImageRegistry { } impl WebrenderExternalImageRegistry { - pub fn new() -> Self { - Self { - external_images: HashMap::new(), - next_image_id: 0, - } - } - pub fn next_id(&mut self, handler_type: WebrenderImageHandlerType) -> ExternalImageId { self.next_image_id += 1; let key = ExternalImageId(self.next_image_id); @@ -84,7 +76,7 @@ pub struct WebrenderExternalImageHandlers { impl WebrenderExternalImageHandlers { pub fn new() -> (Self, Arc>) { - let external_images = Arc::new(Mutex::new(WebrenderExternalImageRegistry::new())); + let external_images = Arc::new(Mutex::new(WebrenderExternalImageRegistry::default())); ( Self { webgl_handler: None, @@ -114,12 +106,7 @@ impl ExternalImageHandler for WebrenderExternalImageHandlers { /// image content. /// The WR client should not change the image content until the /// unlock() call. - fn lock( - &mut self, - key: ExternalImageId, - _channel_index: u8, - _rendering: ImageRendering, - ) -> ExternalImage { + fn lock(&mut self, key: ExternalImageId, _channel_index: u8) -> ExternalImage { let external_images = self.external_images.lock().unwrap(); let handler_type = external_images .get(&key) diff --git a/components/url/lib.rs b/components/url/lib.rs index f9576cce161..89ff2c3f96b 100644 --- a/components/url/lib.rs +++ b/components/url/lib.rs @@ -176,7 +176,7 @@ impl ServoUrl { // Strip `scheme://`, which is hardly useful for identifying websites let mut st = self.as_str(); st = st.strip_prefix(self.scheme()).unwrap_or(st); - st = st.strip_prefix(":").unwrap_or(st); + st = st.strip_prefix(':').unwrap_or(st); st = st.trim_start_matches('/'); // Don't want to return an empty string diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index 435d9a13dba..6eb883374e8 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -101,8 +101,8 @@ impl Handler { actions_by_tick: &[ActionSequence], ) -> Result<(), ErrorStatus> { for tick_actions in actions_by_tick.iter() { - let tick_duration = compute_tick_duration(&tick_actions); - self.dispatch_tick_actions(&tick_actions, tick_duration)?; + let tick_duration = compute_tick_duration(tick_actions); + self.dispatch_tick_actions(tick_actions, tick_duration)?; } Ok(()) } @@ -144,10 +144,10 @@ impl Handler { .or_insert(InputSourceState::Key(KeyInputState::new())); match action { KeyAction::Down(action) => { - self.dispatch_keydown_action(&source_id, &action) + self.dispatch_keydown_action(source_id, action) }, KeyAction::Up(action) => { - self.dispatch_keyup_action(&source_id, &action) + self.dispatch_keyup_action(source_id, action) }, }; }, @@ -174,15 +174,15 @@ impl Handler { match action { PointerAction::Cancel => (), PointerAction::Down(action) => { - self.dispatch_pointerdown_action(&source_id, &action) + self.dispatch_pointerdown_action(source_id, action) }, PointerAction::Move(action) => self.dispatch_pointermove_action( - &source_id, - &action, + source_id, + action, tick_duration, )?, PointerAction::Up(action) => { - self.dispatch_pointerup_action(&source_id, &action) + self.dispatch_pointerup_action(source_id, action) }, } }, @@ -435,6 +435,7 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-perform-a-pointer-move + #[allow(clippy::too_many_arguments)] fn perform_pointer_move( &mut self, source_id: &str, @@ -470,11 +471,7 @@ impl Handler { }; // Step 3 - let last = if 1.0 - duration_ratio < 0.001 { - true - } else { - false - }; + let last = 1.0 - duration_ratio < 0.001; // Step 4 let (x, y) = if last { diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 50337ecaa0a..2793be805b1 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -67,7 +67,7 @@ use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler}; use crate::actions::{InputSourceState, PointerInputState}; fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> { - return vec![ + vec![ ( Method::POST, "/session/{sessionId}/servo/prefs/get", @@ -83,7 +83,7 @@ fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> { "/session/{sessionId}/servo/prefs/reset", ServoExtensionRoute::ResetPrefs, ), - ]; + ] } fn cookie_msg_to_cookie(cookie: cookie::Cookie) -> Cookie { @@ -157,8 +157,8 @@ impl WebDriverSession { ) -> WebDriverSession { WebDriverSession { id: Uuid::new_v4(), - browsing_context_id: browsing_context_id, - top_level_browsing_context_id: top_level_browsing_context_id, + browsing_context_id, + top_level_browsing_context_id, script_timeout: Some(30_000), load_timeout: 300_000, @@ -189,6 +189,7 @@ struct Handler { } #[derive(Clone, Copy, Debug, PartialEq)] +#[allow(clippy::enum_variant_names)] enum ServoExtensionRoute { GetPrefs, SetPrefs, @@ -222,6 +223,7 @@ impl WebDriverExtensionRoute for ServoExtensionRoute { } #[derive(Clone, Debug, PartialEq)] +#[allow(clippy::enum_variant_names)] enum ServoExtensionCommand { GetPrefs(GetPrefsParameters), SetPrefs(SetPrefsParameters), @@ -251,7 +253,7 @@ impl Serialize for SendableWebDriverJSValue { WebDriverJSValue::Null => serializer.serialize_unit(), WebDriverJSValue::Boolean(x) => serializer.serialize_bool(x), WebDriverJSValue::Number(x) => serializer.serialize_f64(x), - WebDriverJSValue::String(ref x) => serializer.serialize_str(&x), + WebDriverJSValue::String(ref x) => serializer.serialize_str(x), WebDriverJSValue::Element(ref x) => x.serialize(serializer), WebDriverJSValue::Frame(ref x) => x.serialize(serializer), WebDriverJSValue::Window(ref x) => x.serialize(serializer), @@ -279,7 +281,7 @@ impl Serialize for WebDriverPrefValue { { match self.0 { PrefValue::Bool(b) => serializer.serialize_bool(b), - PrefValue::Str(ref s) => serializer.serialize_str(&s), + PrefValue::Str(ref s) => serializer.serialize_str(s), PrefValue::Float(f) => serializer.serialize_f64(f), PrefValue::Int(i) => serializer.serialize_i64(i), PrefValue::Missing => serializer.serialize_unit(), @@ -407,7 +409,7 @@ impl Handler { load_status_sender, load_status_receiver, session: None, - constellation_chan: constellation_chan, + constellation_chan, resize_timeout: 500, } } @@ -713,14 +715,8 @@ impl Handler { params: &WindowRectParameters, ) -> WebDriverResult { let (sender, receiver) = ipc::channel().unwrap(); - let width = match params.width { - Some(v) => v, - None => 0, - }; - let height = match params.height { - Some(v) => v, - None => 0, - }; + let width = params.width.unwrap_or(0); + let height = params.height.unwrap_or(0); let size = Size2D::new(width as u32, height as u32); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id; let cmd_msg = WebDriverCommandMsg::SetWindowSize( @@ -1368,7 +1364,7 @@ impl Handler { let input_cancel_list = { let session = self.session_mut()?; session.input_cancel_list.reverse(); - mem::replace(&mut session.input_cancel_list, Vec::new()) + mem::take(&mut session.input_cancel_list) }; if let Err(error) = self.dispatch_actions(&input_cancel_list) { @@ -1471,7 +1467,7 @@ impl Handler { receiver .recv() .unwrap() - .or_else(|error| Err(WebDriverError::new(error, "")))?; + .map_err(|error| WebDriverError::new(error, ""))?; let input_events = send_keys(&keys.text); @@ -1629,12 +1625,10 @@ impl Handler { serde_json::to_value(encoded)?, ))) }, - Err(_) => { - return Err(WebDriverError::new( - ErrorStatus::StaleElementReference, - "Element not found", - )); - }, + Err(_) => Err(WebDriverError::new( + ErrorStatus::StaleElementReference, + "Element not found", + )), } } @@ -1662,7 +1656,7 @@ impl Handler { &self, parameters: &SetPrefsParameters, ) -> WebDriverResult { - for &(ref key, ref value) in parameters.prefs.iter() { + for (key, value) in parameters.prefs.iter() { prefs::pref_map() .set(key, value.0.clone()) .expect("Failed to set preference"); @@ -1674,7 +1668,7 @@ impl Handler { &self, parameters: &GetPrefsParameters, ) -> WebDriverResult { - let prefs = if parameters.prefs.len() == 0 { + let prefs = if parameters.prefs.is_empty() { prefs::pref_map().reset_all(); BTreeMap::new() } else { diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs index 7f95db0850f..14210d1e683 100644 --- a/components/webgpu/lib.rs +++ b/components/webgpu/lib.rs @@ -54,6 +54,7 @@ const DEVICE_POLL_INTERVAL: u64 = 100; pub const PRESENTATION_BUFFER_COUNT: usize = 10; #[derive(Debug, Deserialize, Serialize)] +#[allow(clippy::large_enum_variant)] pub enum WebGPUResponse { RequestAdapter { adapter_info: wgt::AdapterInfo, @@ -330,6 +331,12 @@ impl WebGPU { } } +type WebGPUBufferMaps<'a> = + HashMap>>>; +type WebGPUPresentBufferMaps<'a> = + HashMap, WebGPURequest)>>>; + +#[allow(clippy::upper_case_acronyms)] // Name of the library struct WGPU<'a> { receiver: IpcReceiver<(Option, WebGPURequest)>, sender: IpcSender<(Option, WebGPURequest)>, @@ -340,10 +347,9 @@ struct WGPU<'a> { // Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid _invalid_adapters: Vec, // Buffers with pending mapping - buffer_maps: HashMap>>>, + buffer_maps: WebGPUBufferMaps<'a>, // Presentation Buffers with pending mapping - present_buffer_maps: - HashMap, WebGPURequest)>>>, + present_buffer_maps: WebGPUPresentBufferMaps<'a>, //TODO: Remove this (https://github.com/gfx-rs/wgpu/issues/867) error_command_encoders: RefCell>, webrender_api: RenderApi, @@ -919,8 +925,8 @@ impl<'a> WGPU<'a> { pipeline_id, } => { let desc = DeviceDescriptor { - label: descriptor.label.as_ref().map(|l| crate::Cow::from(l)), - features: descriptor.features.clone(), + label: descriptor.label.as_ref().map(crate::Cow::from), + features: descriptor.features, limits: descriptor.limits.clone(), }; let global = &self.global; @@ -1336,20 +1342,12 @@ webgpu_resource!(WebGPUSurface, id::SurfaceId); webgpu_resource!(WebGPUTexture, id::TextureId); webgpu_resource!(WebGPUTextureView, id::TextureViewId); +#[derive(Default)] pub struct WGPUExternalImages { pub images: Arc>>, pub locked_ids: HashMap>, } -impl WGPUExternalImages { - pub fn new() -> Self { - Self { - images: Arc::new(Mutex::new(HashMap::new())), - locked_ids: HashMap::new(), - } - } -} - impl WebrenderExternalImageApi for WGPUExternalImages { fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D) { let size; diff --git a/docs/COMMAND_LINE_ARGS.md b/docs/COMMAND_LINE_ARGS.md index 70ef19bebd0..aee3d81fc8b 100644 --- a/docs/COMMAND_LINE_ARGS.md +++ b/docs/COMMAND_LINE_ARGS.md @@ -11,7 +11,7 @@ Only arguments that need more explanation will be documented here. # Run ## Enable Experimental Features -Use `--pref` to enable experimental features like experimental DOM API, JavaScript API and CSS properties. +Use `--pref` to enable experimental features like experimental DOM APIs, JavaScript APIs and CSS properties. e.g. To enable Web VR and Bluetooth features: ``` diff --git a/docs/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md index 49f69e65855..04aa0b5900f 100644 --- a/docs/STYLE_GUIDE.md +++ b/docs/STYLE_GUIDE.md @@ -5,10 +5,10 @@ automated linters. This document has guidelines that are less easy to lint for. ## Shell scripts -Shell scripts are OK for small tasks or wrappers, but prefer to use Python for +Shell scripts are suitable for small tasks or wrappers, but it's preferable to use Python for anything with a hint of complexity or in general. -Shell scripts should be written against bash, starting with this shebang: +Shell scripts should be written using bash, starting with this shebang: ``` #!/usr/bin/env bash ``` @@ -23,7 +23,7 @@ set -o nounset set -o pipefail ``` -Quote all variables, using the full form: `"${SOME_VARIABLE}"`. +Rememeber to quote all variables, using the full form: `"${SOME_VARIABLE}"`. Use `"$(some-command)"` instead of backticks for command substitution. Note that these should be quoted as well. diff --git a/docs/components/style.md b/docs/components/style.md index d8d54124fab..12da45f8672 100644 --- a/docs/components/style.md +++ b/docs/components/style.md @@ -1,15 +1,15 @@ # Servo's style system overview -This needs to be filled more extensively. Meanwhile, you can also take a look at -the [style doc comments][style-doc], or the [Styling -Overview][wiki-styling-overview] in the wiki, a conversation between +This document provides an overview of Servo's style system. For more extensive details, +refer to the [style doc comments][style-doc], or the [Styling +Overview][wiki-styling-overview] in the wiki, which includes a conversation between Boris Zbarsky and Patrick Walton about how style sharing works. ## Selector Implementation -In order to be sharable and compatible with Stylo (a project that aims -to integrate Servo's style system into Gecko), the style must be consistent. +To ensure compatibility with Stylo (a project integrating Servo's style system into Gecko), +selectors must be consistent. The consistency is implemented in [selectors' SelectorImpl][selector-impl], containing the logic related to parsing pseudo-elements and other pseudo-classes diff --git a/docs/components/webxr.md b/docs/components/webxr.md index 9b614ba9d16..f366b069886 100644 --- a/docs/components/webxr.md +++ b/docs/components/webxr.md @@ -2,22 +2,22 @@ ## Terminology -There are three main components involved in Servo's WebXR implementation: -1. the script thread (runs all JS for a page) -2. the WebGL thread (maintains WebGL canvas data and invokes GL operations corresponding to [WebGL APIs](https://registry.khronos.org/webgl/specs/latest/1.0/)) -3. the compositor (AKA the main thread) +Servo's WebXR implementation involves three main components: +1. The script thread (runs all JS for a page) +2. The WebGL thread (maintains WebGL canvas data and invokes GL operations corresponding to [WebGL APIs](https://registry.khronos.org/webgl/specs/latest/1.0/)) +3. The compositor (AKA the main thread) Additionally, there are a number of WebXR-specific concepts: -* the [discovery object](https://doc.servo.org/webxr_api/trait.DiscoveryAPI.html) (ie. how Servo discovers if a device can provide a WebXR session) -* the [WebXR registry](https://doc.servo.org/webxr_api/struct.MainThreadRegistry.html) (the compositor's interface to WebXR) -* the [layer manager](https://doc.servo.org/webxr_api/layer/trait.LayerManagerAPI.html) (manages WebXR layers for a given session and frame operations on those layers) -* ths [layer grand manager](https://doc.servo.org/webxr_api/layer/trait.LayerGrandManagerAPI.html) (manages all layer managers for WebXR sessions) +* The [discovery object](https://doc.servo.org/webxr_api/trait.DiscoveryAPI.html) (ie. how Servo discovers if a device can provide a WebXR session) +* The [WebXR registry](https://doc.servo.org/webxr_api/struct.MainThreadRegistry.html) (the compositor's interface to WebXR) +* The [layer manager](https://doc.servo.org/webxr_api/layer/trait.LayerManagerAPI.html) (manages WebXR layers for a given session and frame operations on those layers) +* The [layer grand manager](https://doc.servo.org/webxr_api/layer/trait.LayerGrandManagerAPI.html) (manages all layer managers for WebXR sessions) Finally, there are graphics-specific concepts that are important for the low-level details of rendering with WebXR: * [surfman](https://github.com/servo/webxr/blob/main/webxr/glwindow/mod.rs#L448-L452) is a crate that abstracts away platform-specific details of OpenGL hardware-accelerated rendering -* a [surface](https://doc.servo.org/surfman/platform/unix/default/surface/type.Surface.html) is a hardware buffer that are tied to a specific OpenGL context -* a [surface texture](https://doc.servo.org/surfman/platform/unix/default/surface/type.SurfaceTexture.html) is an OpenGL texture that wraps a surface. Surface textures can be shared between OpenGL contexts. -* a [surfman context](https://doc.servo.org/surfman/platform/unix/default/context/type.Context.html) represents a particular OpenGL context, and is backed by platform-specific implementations (such as EGL on Unix-based platforms) +* [surface](https://doc.servo.org/surfman/platform/unix/default/surface/type.Surface.html) is a hardware buffer that are tied to a specific OpenGL context +* [surface texture](https://doc.servo.org/surfman/platform/unix/default/surface/type.SurfaceTexture.html) is an OpenGL texture that wraps a surface. Surface textures can be shared between OpenGL contexts. +* [surfman context](https://doc.servo.org/surfman/platform/unix/default/context/type.Context.html) represents a particular OpenGL context, and is backed by platform-specific implementations (such as EGL on Unix-based platforms) * [ANGLE](https://github.com/servo/mozangle/) is an OpenGL implementation on top of Direct3D which is used in Servo to provide a consistent OpenGL backend on Windows-based platforms ## How Servo's compositor starts diff --git a/etc/ci/report_aggregated_expected_results.py b/etc/ci/report_aggregated_expected_results.py index 21c2d6b2431..ac93951ca6e 100755 --- a/etc/ci/report_aggregated_expected_results.py +++ b/etc/ci/report_aggregated_expected_results.py @@ -37,7 +37,7 @@ class Item: def from_result(cls, result: dict, title: Optional[str] = None, print_stack=True): expected = result["expected"] actual = result["actual"] - title = title if title else result["path"] + title = title if title else f'`{result["path"]}`' if expected != actual: title = f"{actual} [expected {expected}] {title}" else: @@ -51,12 +51,15 @@ class Item: stack = result["stack"] if result["stack"] and print_stack else "" body = f"{result['message']}\n{stack}".strip() + if body: + body = f"\n```\n{body}\n```\n" subtest_results = result.get("unexpected_subtest_results", []) children = [ cls.from_result( subtest_result, - f"subtest: {subtest_result['subtest']} {subtest_result.get('message', '')}", + f"subtest: `{subtest_result['subtest']}`" + + (f" \n```\n{subtest_result['message']}\n```\n" if subtest_result['message'] else ""), False) for subtest_result in subtest_results ] @@ -69,7 +72,7 @@ class Item: " " * len(indent + bullet)) output += "\n".join([child.to_string("• ", indent + " ") for child in self.children]) - return output.rstrip() + return output.rstrip().replace("`", "") def to_html(self, level: int = 0) -> ElementTree.Element: if level == 0: diff --git a/etc/shell.nix b/etc/shell.nix index 788aad42537..957011a1b22 100644 --- a/etc/shell.nix +++ b/etc/shell.nix @@ -71,7 +71,9 @@ stdenv.mkDerivation (androidEnvironment // rec { gst_all_1.gstreamer gst_all_1.gst-plugins-base + gst_all_1.gst-plugins-good gst_all_1.gst-plugins-bad + gst_all_1.gst-plugins-ugly rustup taplo diff --git a/ports/jniapi/Cargo.toml b/ports/jniapi/Cargo.toml index 533769a913b..c8fa1f4e8cd 100644 --- a/ports/jniapi/Cargo.toml +++ b/ports/jniapi/Cargo.toml @@ -44,7 +44,7 @@ js_backtrace = ["libservo/js_backtrace"] max_log_level = ["log/release_max_level_info"] media-gstreamer = ["libservo/media-gstreamer"] native-bluetooth = ["libservo/native-bluetooth"] -no_static_freetype = ["libservo/no_static_freetype"] +dynamic_freetype = ["libservo/dynamic_freetype"] no-wgl = ["libservo/no-wgl"] profilemozjs = ["libservo/profilemozjs"] refcell_backtrace = ["libservo/refcell_backtrace"] diff --git a/ports/jniapi/src/simpleservo.rs b/ports/jniapi/src/simpleservo.rs index 1d48f18b0ab..719c9c64644 100644 --- a/ports/jniapi/src/simpleservo.rs +++ b/ports/jniapi/src/simpleservo.rs @@ -896,7 +896,7 @@ impl WindowMethods for ServoWindowCallbacks { fn get_coordinates(&self) -> EmbedderCoordinates { let coords = self.coordinates.borrow(); EmbedderCoordinates { - viewport: coords.viewport, + viewport: coords.viewport.to_box2d(), framebuffer: coords.framebuffer, window: (coords.viewport.size, Point2D::new(0, 0)), screen: coords.viewport.size, diff --git a/ports/servoshell/app.rs b/ports/servoshell/app.rs index 853863c247f..45fa7c1b68b 100644 --- a/ports/servoshell/app.rs +++ b/ports/servoshell/app.rs @@ -138,19 +138,7 @@ impl App { let ev_waker = events_loop.create_event_loop_waker(); events_loop.run_forever(move |event, w, control_flow| { let now = Instant::now(); - match event { - // Uncomment to filter out logging of common events, which can be very noisy. - // winit::event::Event::DeviceEvent { .. } => {}, - // winit::event::Event::WindowEvent { - // event: WindowEvent::CursorMoved { .. }, - // .. - // } => {}, - // winit::event::Event::MainEventsCleared => {}, - // winit::event::Event::RedrawEventsCleared => {}, - // winit::event::Event::UserEvent(..) => {}, - // winit::event::Event::NewEvents(..) => {}, - _ => trace!("@{:?} (+{:?}) {:?}", now - t_start, now - t, event), - } + trace_winit_event!(event, "@{:?} (+{:?}) {event:?}", now - t_start, now - t); t = now; match event { winit::event::Event::NewEvents(winit::event::StartCause::Init) => { @@ -426,7 +414,7 @@ impl App { // Catch some keyboard events, and push the rest onto the WebViewManager event queue. webviews.handle_window_events(embedder_events); - if webviews.webview_id().is_some() { + if pref!(dom.gamepad.enabled) && webviews.webview_id().is_some() { webviews.handle_gamepad_events(); } diff --git a/ports/servoshell/headed_window.rs b/ports/servoshell/headed_window.rs index 30e30950ef5..35ddaca7498 100644 --- a/ports/servoshell/headed_window.rs +++ b/ports/servoshell/headed_window.rs @@ -526,12 +526,12 @@ impl WindowMethods for Window { let window_origin = winit_position_to_euclid_point(window_origin).to_i32(); let viewport_origin = DeviceIntPoint::zero(); // bottom left let viewport_size = winit_size_to_euclid_size(self.winit_window.inner_size()).to_f32(); - let viewport = DeviceIntRect::new(viewport_origin, viewport_size.to_i32()); + let viewport = DeviceIntRect::from_origin_and_size(viewport_origin, viewport_size.to_i32()); let screen = self.screen_size.to_i32(); EmbedderCoordinates { viewport, - framebuffer: viewport.size, + framebuffer: viewport.size(), window: (window_size, window_origin), screen, // FIXME: Winit doesn't have API for available size. Fallback to screen size diff --git a/ports/servoshell/headless_window.rs b/ports/servoshell/headless_window.rs index fe040d62204..dbad76680e6 100644 --- a/ports/servoshell/headless_window.rs +++ b/ports/servoshell/headless_window.rs @@ -166,7 +166,7 @@ impl WindowMethods for Window { .unwrap_or(None) .map(|info| Size2D::from_untyped(info.size)) .unwrap_or(Size2D::new(0, 0)); - let viewport = DeviceIntRect::new(Point2D::zero(), size); + let viewport = DeviceIntRect::from_origin_and_size(Point2D::zero(), size); EmbedderCoordinates { viewport, framebuffer: size, diff --git a/ports/servoshell/lib.rs b/ports/servoshell/lib.rs index 2c24e11572b..5a99d34a3ed 100644 --- a/ports/servoshell/lib.rs +++ b/ports/servoshell/lib.rs @@ -9,6 +9,9 @@ #[macro_use] extern crate sig; +#[macro_use] +mod tracing; + #[cfg(test)] mod test; @@ -96,9 +99,6 @@ pub fn main() { ArgumentParsingResult::ContentProcess(matches, token) => { opts_matches = matches; content_process_token = Some(token); - if opts::get().is_running_problem_test && env::var("RUST_LOG").is_err() { - env::set_var("RUST_LOG", "compositing::constellation"); - } }, ArgumentParsingResult::ChromeProcess(matches) => { opts_matches = matches; diff --git a/ports/servoshell/tracing.rs b/ports/servoshell/tracing.rs new file mode 100644 index 00000000000..c35ce0d9916 --- /dev/null +++ b/ports/servoshell/tracing.rs @@ -0,0 +1,229 @@ +/* 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/. */ + +/// Log an event from winit ([winit::event::Event]) at trace level. +/// - To disable tracing: RUST_LOG='servoshell { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Log an event from servo ([servo::embedder_traits::EmbedderMsg]) at trace level. +/// - To disable tracing: RUST_LOG='servoshell { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Log an event to servo ([servo::compositing::windowing::EmbedderEvent]) at trace level. +/// - To disable tracing: RUST_LOG='servoshell>servo@=off' +/// - To enable tracing: RUST_LOG='servoshell>servo@' +/// - Recommended filters when tracing is enabled: +/// - servoshell>servo@Idle=off +/// - servoshell>servo@MouseWindowMoveEventClass=off +macro_rules! trace_embedder_event { + // This macro only exists to put the docs in the same file as the target prefix, + // so the macro definition is always the same. + ($event:expr, $($rest:tt)+) => { + ::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+) + }; +} + +/// Get the log target for an event, as a static string. +pub(crate) trait LogTarget { + fn log_target(&self) -> &'static str; +} + +mod from_winit { + use super::LogTarget; + use crate::events_loop::WakerEvent; + + macro_rules! target { + ($($name:literal)+) => { + concat!("servoshell { + fn log_target(&self) -> &'static str { + use winit::event::StartCause; + match self { + Self::NewEvents(start_cause) => match start_cause { + StartCause::ResumeTimeReached { .. } => target!("NewEvents(ResumeTimeReached)"), + StartCause::WaitCancelled { .. } => target!("NewEvents(WaitCancelled)"), + StartCause::Poll => target!("NewEvents(Poll)"), + StartCause::Init => target!("NewEvents(Init)"), + }, + Self::WindowEvent { event, .. } => event.log_target(), + Self::DeviceEvent { .. } => target!("DeviceEvent"), + Self::UserEvent(WakerEvent) => target!("UserEvent(WakerEvent)"), + Self::Suspended => target!("Suspended"), + Self::Resumed => target!("Resumed"), + Self::MainEventsCleared => target!("MainEventsCleared"), + Self::RedrawRequested(_) => target!("RedrawRequested"), + Self::RedrawEventsCleared => target!("RedrawEventsCleared"), + Self::LoopDestroyed => target!("LoopDestroyed"), + } + } + } + + impl LogTarget for winit::event::WindowEvent<'_> { + fn log_target(&self) -> &'static str { + macro_rules! target_variant { + ($name:literal) => { + target!("WindowEvent(" $name ")") + }; + } + match self { + Self::Resized(_) => target_variant!("Resized"), + Self::Moved(_) => target_variant!("Moved"), + Self::CloseRequested => target_variant!("CloseRequested"), + Self::Destroyed => target_variant!("Destroyed"), + Self::DroppedFile(_) => target_variant!("DroppedFile"), + Self::HoveredFile(_) => target_variant!("HoveredFile"), + Self::HoveredFileCancelled => target_variant!("HoveredFileCancelled"), + Self::ReceivedCharacter(_) => target_variant!("ReceivedCharacter"), + Self::Focused(_) => target_variant!("Focused"), + Self::KeyboardInput { .. } => target_variant!("KeyboardInput"), + Self::ModifiersChanged(_) => target_variant!("ModifiersChanged"), + Self::Ime(_) => target_variant!("Ime"), + Self::CursorMoved { .. } => target_variant!("CursorMoved"), + Self::CursorEntered { .. } => target_variant!("CursorEntered"), + Self::CursorLeft { .. } => target_variant!("CursorLeft"), + Self::MouseWheel { .. } => target_variant!("MouseWheel"), + Self::MouseInput { .. } => target_variant!("MouseInput"), + Self::TouchpadMagnify { .. } => target_variant!("TouchpadMagnify"), + Self::SmartMagnify { .. } => target_variant!("SmartMagnify"), + Self::TouchpadRotate { .. } => target_variant!("TouchpadRotate"), + Self::TouchpadPressure { .. } => target_variant!("TouchpadPressure"), + Self::AxisMotion { .. } => target_variant!("AxisMotion"), + Self::Touch(_) => target_variant!("Touch"), + Self::ScaleFactorChanged { .. } => target_variant!("ScaleFactorChanged"), + Self::ThemeChanged(_) => target_variant!("ThemeChanged"), + Self::Occluded(_) => target_variant!("Occluded"), + } + } + } +} + +mod from_servo { + use super::LogTarget; + + macro_rules! target { + ($($name:literal)+) => { + concat!("servoshell &'static str { + match self { + Self::Status(_) => target!("Status"), + Self::ChangePageTitle(_) => target!("ChangePageTitle"), + Self::MoveTo(_) => target!("MoveTo"), + Self::ResizeTo(_) => target!("ResizeTo"), + Self::Prompt(_, _) => target!("Prompt"), + Self::ShowContextMenu(_, _, _) => target!("ShowContextMenu"), + Self::AllowNavigationRequest(_, _) => target!("AllowNavigationRequest"), + Self::AllowOpeningWebView(_) => target!("AllowOpeningWebView"), + Self::WebViewOpened(_) => target!("WebViewOpened"), + Self::WebViewClosed(_) => target!("WebViewClosed"), + Self::WebViewFocused(_) => target!("WebViewFocused"), + Self::WebViewBlurred => target!("WebViewBlurred"), + Self::AllowUnload(_) => target!("AllowUnload"), + Self::Keyboard(_) => target!("Keyboard"), + Self::GetClipboardContents(_) => target!("GetClipboardContents"), + Self::SetClipboardContents(_) => target!("SetClipboardContents"), + Self::SetCursor(_) => target!("SetCursor"), + Self::NewFavicon(_) => target!("NewFavicon"), + Self::HeadParsed => target!("HeadParsed"), + Self::HistoryChanged(_, _) => target!("HistoryChanged"), + Self::SetFullscreenState(_) => target!("SetFullscreenState"), + Self::LoadStart => target!("LoadStart"), + Self::LoadComplete => target!("LoadComplete"), + Self::Panic(_, _) => target!("Panic"), + Self::GetSelectedBluetoothDevice(_, _) => target!("GetSelectedBluetoothDevice"), + Self::SelectFiles(_, _, _) => target!("SelectFiles"), + Self::PromptPermission(_, _) => target!("PromptPermission"), + Self::ShowIME(_, _, _, _) => target!("ShowIME"), + Self::HideIME => target!("HideIME"), + Self::Shutdown => target!("Shutdown"), + Self::ReportProfile(_) => target!("ReportProfile"), + Self::MediaSessionEvent(_) => target!("MediaSessionEvent"), + Self::OnDevtoolsStarted(_, _) => target!("OnDevtoolsStarted"), + Self::ReadyToPresent => target!("ReadyToPresent"), + Self::EventDelivered(_) => target!("EventDelivered"), + } + } + } +} + +mod to_servo { + use super::LogTarget; + + macro_rules! target { + ($($name:literal)+) => { + concat!("servoshell>servo@", $($name),+) + }; + } + + impl LogTarget for servo::compositing::windowing::EmbedderEvent { + fn log_target(&self) -> &'static str { + match self { + Self::Idle => target!("Idle"), + Self::Refresh => target!("Refresh"), + Self::Resize => target!("Resize"), + Self::AllowNavigationResponse(_, _) => target!("AllowNavigationResponse"), + Self::LoadUrl(_, _) => target!("LoadUrl"), + Self::MouseWindowEventClass(_) => target!("MouseWindowEventClass"), + Self::MouseWindowMoveEventClass(_) => target!("MouseWindowMoveEventClass"), + Self::Touch(_, _, _) => target!("Touch"), + Self::Wheel(_, _) => target!("Wheel"), + Self::Scroll(_, _, _) => target!("Scroll"), + Self::Zoom(_) => target!("Zoom"), + Self::PinchZoom(_) => target!("PinchZoom"), + Self::ResetZoom => target!("ResetZoom"), + Self::Navigation(_, _) => target!("Navigation"), + Self::Quit => target!("Quit"), + Self::ExitFullScreen(_) => target!("ExitFullScreen"), + Self::Keyboard(_) => target!("Keyboard"), + Self::Reload(_) => target!("Reload"), + Self::NewWebView(_, _) => target!("NewWebView"), + Self::CloseWebView(_) => target!("CloseWebView"), + Self::SendError(_, _) => target!("SendError"), + Self::FocusWebView(_) => target!("FocusWebView"), + Self::ToggleWebRenderDebug(_) => target!("ToggleWebRenderDebug"), + Self::CaptureWebRender => target!("CaptureWebRender"), + Self::ClearCache => target!("ClearCache"), + Self::ToggleSamplingProfiler(_, _) => target!("ToggleSamplingProfiler"), + Self::MediaSessionAction(_) => target!("MediaSessionAction"), + Self::WebViewVisibilityChanged(_, _) => target!("WebViewVisibilityChanged"), + Self::IMEDismissed => target!("IMEDismissed"), + Self::InvalidateNativeSurface => target!("InvalidateNativeSurface"), + Self::ReplaceNativeSurface(_, _) => target!("ReplaceNativeSurface"), + Self::Gamepad(_) => target!("Gamepad"), + } + } + } +} diff --git a/ports/servoshell/webview.rs b/ports/servoshell/webview.rs index 512ee5a4326..a182a4f8962 100644 --- a/ports/servoshell/webview.rs +++ b/ports/servoshell/webview.rs @@ -134,7 +134,7 @@ where pub fn handle_window_events(&mut self, events: Vec) { for event in events { - trace!("embedder <- window EmbedderEvent {:?}", event); + trace_embedder_event!(event, "{event:?}"); match event { EmbedderEvent::Keyboard(key_event) => { self.handle_key_from_window(key_event); @@ -434,11 +434,11 @@ where let mut need_present = false; let mut history_changed = false; for (webview_id, msg) in events { - trace!( - "embedder <- servo EmbedderMsg ({:?}, {:?})", - webview_id.map(|x| format!("{}", x)), - msg - ); + if let Some(webview_id) = webview_id { + trace_embedder_msg!(msg, "{webview_id} {msg:?}"); + } else { + trace_embedder_msg!(msg, "{msg:?}"); + } match msg { EmbedderMsg::Status(_status) => { // FIXME: surface this status string in the UI somehow diff --git a/python/servo/devenv_commands.py b/python/servo/devenv_commands.py index 7e4cf49e56e..a12e92aed3b 100644 --- a/python/servo/devenv_commands.py +++ b/python/servo/devenv_commands.py @@ -139,7 +139,9 @@ class MachCommands(CommandBase): self.ensure_bootstrapped() self.ensure_clobbered() - return self.run_cargo_build_like_command("clippy", params, **kwargs) + env = self.build_env() + env['RUSTC'] = 'rustc' + return self.run_cargo_build_like_command("clippy", params, env=env, **kwargs) @Command('grep', description='`git grep` for selected directories.', diff --git a/python/servo/platform/linux.py b/python/servo/platform/linux.py index 8e79ed34391..d954869c8dd 100644 --- a/python/servo/platform/linux.py +++ b/python/servo/platform/linux.py @@ -54,7 +54,8 @@ DNF_PKGS = ['libtool', 'gcc-c++', 'libXi-devel', 'freetype-devel', 'dbus-devel', 'ncurses-devel', 'harfbuzz-devel', 'ccache', 'clang', 'clang-libs', 'llvm', 'python3-devel', 'gstreamer1-devel', 'gstreamer1-plugins-base-devel', - 'gstreamer1-plugins-bad-free-devel', 'libjpeg-turbo-devel', + 'gstreamer1-plugins-good', 'gstreamer1-plugins-bad-free-devel', + 'gstreamer1-plugins-ugly-free', 'libjpeg-turbo-devel', 'zlib', 'libjpeg', 'vulkan-loader'] # https://voidlinux.org/packages/ @@ -68,8 +69,9 @@ XBPS_PKGS = ['libtool', 'gcc', 'libXi-devel', 'freetype-devel', 'fontconfig-devel', 'cabextract', 'expat-devel', 'cmake', 'cmake', 'libXcursor-devel', 'libXmu-devel', 'dbus-devel', 'ncurses-devel', 'harfbuzz-devel', 'ccache', 'glu-devel', - 'clang', 'gstreamer1-devel', - 'gst-plugins-base1-devel', 'gst-plugins-bad1-devel', 'vulkan-loader'] + 'clang', 'gstreamer1-devel', 'gst-plugins-base1-devel', + 'gst-plugins-good1', 'gst-plugins-bad1-devel', + 'gst-plugins-ugly1', 'vulkan-loader'] GSTREAMER_URL = \ "https://github.com/servo/servo-build-deps/releases/download/linux/gstreamer-1.16-x86_64-linux-gnu.20190515.tar.gz" diff --git a/resources/servo.css b/resources/servo.css index 6bea1cc43ad..4d32867e0ff 100644 --- a/resources/servo.css +++ b/resources/servo.css @@ -230,20 +230,16 @@ svg > * { overflow: visible; } +*|*::-servo-anonymous-table { + display: table; +} + *|*::-servo-anonymous-table-row { display: table-row; - position: static; - border: none; - counter-increment: none; - overflow: visible; } *|*::-servo-anonymous-table-cell { display: table-cell; - position: static; - border: none; - counter-increment: none; - overflow: visible; } *|*::-servo-legacy-anonymous-block { diff --git a/servo-tidy.toml b/servo-tidy.toml index a5e0496f69e..0c43c7fbc3a 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -68,6 +68,10 @@ packages = [ "phf_codegen", "phf_generator", "phf_shared", + + # These can be removed once winit, font-kit, etc are upgraded + "core-graphics", + "core-text", ] # Files that are ignored for all tidy and lint checks. files = [ diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini index b9630dd4930..fb3e67eab21 100644 --- a/tests/wpt/include.ini +++ b/tests/wpt/include.ini @@ -116,8 +116,6 @@ skip: true skip: true [printing] skip: true - [WOFF2] - skip: true [zoom] skip: true [custom-elements] diff --git a/tests/wpt/meta-legacy-layout/css/CSS2/tables/table-anonymous-objects-213.xht.ini b/tests/wpt/meta-legacy-layout/css/CSS2/tables/table-anonymous-objects-213.xht.ini new file mode 100644 index 00000000000..8052b51007d --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/CSS2/tables/table-anonymous-objects-213.xht.ini @@ -0,0 +1,2 @@ +[table-anonymous-objects-213.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-001.xht.ini new file mode 100644 index 00000000000..54fee55cbad --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-001.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-002.xht.ini new file mode 100644 index 00000000000..1145a6621b2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-002.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-003.xht.ini new file mode 100644 index 00000000000..6384ed1182e --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-003.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-004.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-004.xht.ini new file mode 100644 index 00000000000..0669cb70139 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-004.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-004.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-005.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-005.xht.ini new file mode 100644 index 00000000000..07febdb610e --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-005.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-005.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-006.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-006.xht.ini new file mode 100644 index 00000000000..a0c2a60ddfd --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-006.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-006.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-007.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-007.xht.ini new file mode 100644 index 00000000000..3ace86d0bda --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-007.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-007.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-008.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-008.xht.ini new file mode 100644 index 00000000000..6d305f07cfd --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-extraneous-data-008.xht.ini @@ -0,0 +1,2 @@ +[blocks-extraneous-data-008.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-001.xht.ini new file mode 100644 index 00000000000..d0bcd124fbf --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-001.xht.ini @@ -0,0 +1,2 @@ +[blocks-overlap-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-002.xht.ini new file mode 100644 index 00000000000..69a6390c1db --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-002.xht.ini @@ -0,0 +1,2 @@ +[blocks-overlap-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-003.xht.ini new file mode 100644 index 00000000000..058a8116b56 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/blocks-overlap-003.xht.ini @@ -0,0 +1,2 @@ +[blocks-overlap-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-001.xht.ini new file mode 100644 index 00000000000..470236169fb --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-001.xht.ini @@ -0,0 +1,2 @@ +[datatypes-invalid-base128-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-002.xht.ini new file mode 100644 index 00000000000..3d39ef79d15 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-002.xht.ini @@ -0,0 +1,2 @@ +[datatypes-invalid-base128-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-003.xht.ini new file mode 100644 index 00000000000..802143a29b2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/datatypes-invalid-base128-003.xht.ini @@ -0,0 +1,2 @@ +[datatypes-invalid-base128-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/directory-mismatched-tables-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/directory-mismatched-tables-001.xht.ini new file mode 100644 index 00000000000..75f2888c78d --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/directory-mismatched-tables-001.xht.ini @@ -0,0 +1,2 @@ +[directory-mismatched-tables-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-001.xht.ini new file mode 100644 index 00000000000..effd2f3d4e8 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-001.xht.ini @@ -0,0 +1,2 @@ +[header-length-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-002.xht.ini new file mode 100644 index 00000000000..df76d3823f5 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/header-length-002.xht.ini @@ -0,0 +1,2 @@ +[header-length-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/header-numTables-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/header-numTables-001.xht.ini new file mode 100644 index 00000000000..3faa32884ba --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/header-numTables-001.xht.ini @@ -0,0 +1,2 @@ +[header-numTables-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/header-signature-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/header-signature-001.xht.ini new file mode 100644 index 00000000000..6d51e63c636 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/header-signature-001.xht.ini @@ -0,0 +1,2 @@ +[header-signature-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-001.xht.ini new file mode 100644 index 00000000000..6bd4a2140e5 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-bad-origlength-loca-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-002.xht.ini new file mode 100644 index 00000000000..7fb9751bb04 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-bad-origlength-loca-002.xht.ini @@ -0,0 +1,2 @@ +[tabledata-bad-origlength-loca-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-brotli-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-brotli-001.xht.ini new file mode 100644 index 00000000000..d44a929bc5b --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-brotli-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-brotli-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-001.xht.ini new file mode 100644 index 00000000000..6fcbed11d4c --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-decompressed-length-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-002.xht.ini new file mode 100644 index 00000000000..9ca9ee942de --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-002.xht.ini @@ -0,0 +1,2 @@ +[tabledata-decompressed-length-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-003.xht.ini new file mode 100644 index 00000000000..894c0484e56 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-003.xht.ini @@ -0,0 +1,2 @@ +[tabledata-decompressed-length-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-004.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-004.xht.ini new file mode 100644 index 00000000000..ea70de04fa2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-decompressed-length-004.xht.ini @@ -0,0 +1,2 @@ +[tabledata-decompressed-length-004.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-extraneous-data-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-extraneous-data-001.xht.ini new file mode 100644 index 00000000000..973a3b069b8 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-extraneous-data-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-extraneous-data-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-002.xht.ini new file mode 100644 index 00000000000..063b7f0d07c --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-002.xht.ini @@ -0,0 +1,2 @@ +[tabledata-glyf-bbox-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-003.xht.ini new file mode 100644 index 00000000000..a9ff0d3b050 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-glyf-bbox-003.xht.ini @@ -0,0 +1,2 @@ +[tabledata-glyf-bbox-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-non-zero-loca-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-non-zero-loca-001.xht.ini new file mode 100644 index 00000000000..9ff7438cdb9 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-non-zero-loca-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-non-zero-loca-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-001.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-001.xht.ini new file mode 100644 index 00000000000..caaefb7cd78 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-001.xht.ini @@ -0,0 +1,2 @@ +[tabledata-transform-bad-flag-001.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-002.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-002.xht.ini new file mode 100644 index 00000000000..500b44431b4 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-bad-flag-002.xht.ini @@ -0,0 +1,2 @@ +[tabledata-transform-bad-flag-002.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-003.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-003.xht.ini new file mode 100644 index 00000000000..12216438220 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-003.xht.ini @@ -0,0 +1,2 @@ +[tabledata-transform-hmtx-003.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-004.xht.ini b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-004.xht.ini new file mode 100644 index 00000000000..5c5b25a8b75 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/WOFF2/tabledata-transform-hmtx-004.xht.ini @@ -0,0 +1,2 @@ +[tabledata-transform-hmtx-004.xht] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini index a647125277a..5496474410b 100644 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini +++ b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini @@ -1,2 +1,2 @@ [mix-blend-mode-animation.html] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini deleted file mode 100644 index f4ba42ba597..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-blended-element-interposed.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini deleted file mode 100644 index b88377b7471..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini deleted file mode 100644 index e969ccfd9ae..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-blended-element-with-transparent-pixels.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-3D-transform.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-3D-transform.html.ini deleted file mode 100644 index bad01615f4a..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-3D-transform.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mix-blend-mode-blended-with-3D-transform.html] - type: reftest - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-transform-and-perspective.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-transform-and-perspective.html.ini deleted file mode 100644 index 0e16a4f7db7..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blended-with-transform-and-perspective.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-blended-with-transform-and-perspective.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini deleted file mode 100644 index 51bd95228fb..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-blending-with-sibling.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini deleted file mode 100644 index 3bca294ac5f..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-canvas-parent.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini deleted file mode 100644 index 2bc23c0b9b2..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-canvas-sibling.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini deleted file mode 100644 index 85229ea8e3f..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-iframe-parent.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini deleted file mode 100644 index 17f22fdb1af..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-iframe-sibling.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini deleted file mode 100644 index 7aa3a5aefe5..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-image.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini deleted file mode 100644 index 1f039c2f7aa..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-mask.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini deleted file mode 100644 index e628a53f56c..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-overflowing-child-of-blended-element.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-hidden-and-border-radius.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-hidden-and-border-radius.html.ini deleted file mode 100644 index d2f39d33bd7..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-hidden-and-border-radius.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mix-blend-mode-parent-element-overflow-hidden-and-border-radius.html] - type: reftest - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini deleted file mode 100644 index f0050373a67..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini deleted file mode 100644 index 3260cfddf6f..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-parent-with-3D-transform.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini deleted file mode 100644 index d9d62c6cff4..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-script.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini deleted file mode 100644 index 89b4eb5a86a..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-sibling-with-3D-transform.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini deleted file mode 100644 index b75b4a3d3e2..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-simple.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini deleted file mode 100644 index 8e3c2a518e1..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mix-blend-mode-stacking-context-creates-isolation.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/compositing/root-element-blend-mode.html.ini b/tests/wpt/meta-legacy-layout/css/compositing/root-element-blend-mode.html.ini deleted file mode 100644 index 448b96b4886..00000000000 --- a/tests/wpt/meta-legacy-layout/css/compositing/root-element-blend-mode.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[root-element-blend-mode.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-animations/animation-offscreen-to-onscreen.html.ini b/tests/wpt/meta-legacy-layout/css/css-animations/animation-offscreen-to-onscreen.html.ini new file mode 100644 index 00000000000..9876f879b14 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-animations/animation-offscreen-to-onscreen.html.ini @@ -0,0 +1,2 @@ +[animation-offscreen-to-onscreen.html] + expected: TIMEOUT diff --git a/tests/wpt/meta-legacy-layout/css/css-animations/empty-pseudo-class-with-animation.html.ini b/tests/wpt/meta-legacy-layout/css/css-animations/empty-pseudo-class-with-animation.html.ini new file mode 100644 index 00000000000..5d78e3a8de2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-animations/empty-pseudo-class-with-animation.html.ini @@ -0,0 +1,3 @@ +[empty-pseudo-class-with-animation.html] + [Setting an "animation" style property on an element does not interfere with the :empty pseudo-class.] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-repeat-repeat-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-repeat-repeat-001.html.ini deleted file mode 100644 index bdc1d29468a..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-repeat-repeat-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[border-image-repeat-repeat-001.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-001.html.ini deleted file mode 100644 index 6fc15684d17..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[border-image-slice-fill-001.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-002.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-002.html.ini deleted file mode 100644 index 3641d4be80e..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/border-image-slice-fill-002.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[border-image-slice-fill-002.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/inheritance.sub.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/inheritance.sub.html.ini index 06216373de1..fb8dada39fb 100644 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/inheritance.sub.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-backgrounds/inheritance.sub.html.ini @@ -1,21 +1,6 @@ [inheritance.sub.html] - [Inheritance of CSS Backgrounds and Borders properties] - expected: FAIL - [Property background-position has initial value 0% 0%] expected: FAIL [Property background-position does not inherit] expected: FAIL - - [Property border-bottom-width has initial value undefined] - expected: FAIL - - [Property border-left-width has initial value undefined] - expected: FAIL - - [Property border-right-width has initial value undefined] - expected: FAIL - - [Property border-top-width has initial value undefined] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/background-image-computed.sub.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/background-image-computed.sub.html.ini deleted file mode 100644 index 2a37f75fea3..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/background-image-computed.sub.html.ini +++ /dev/null @@ -1,48 +0,0 @@ -[background-image-computed.sub.html] - [Property background-image value 'conic-gradient(at center, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 45deg at 10px 10px, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 0deg, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(at 10px 10px, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 45deg at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 45deg at center, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 0deg at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 0deg at center, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 45deg, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 0deg at 10px 10px, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'conic-gradient(at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from -45deg, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'conic-gradient(from -45deg at center, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from -45deg at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from -45deg at 10px 10px, red, blue)'] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/border-image-source-computed.sub.html.ini b/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/border-image-source-computed.sub.html.ini index 19f4337a212..2c1e5f88b03 100644 --- a/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/border-image-source-computed.sub.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-backgrounds/parsing/border-image-source-computed.sub.html.ini @@ -1,7 +1,3 @@ [border-image-source-computed.sub.html] [Property border-image-source value 'conic-gradient(from 90deg at 80% 90%, lime, black)' computes to 'conic-gradient(from 90deg at 80% 90%, rgb(0, 255, 0), rgb(0, 0, 0))'] expected: FAIL - - [Property border-image-source value 'conic-gradient(from 90deg at 80% 90%, lime, black)'] - expected: FAIL - diff --git a/tests/wpt/meta-legacy-layout/css/css-color/system-color-consistency.html.ini b/tests/wpt/meta-legacy-layout/css/css-color/system-color-consistency.html.ini index 343156ca80d..d8796787e59 100644 --- a/tests/wpt/meta-legacy-layout/css/css-color/system-color-consistency.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-color/system-color-consistency.html.ini @@ -79,3 +79,171 @@ [Property color value 'MarkText' has the same color as the color of a mark element] expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a button (light)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a button (light)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a button (light)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a submit button (light)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a submit button (light)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a submit button (light)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a reset button (light)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a reset button (light)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a reset button (light)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a color picker (light)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a color picker (light)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a color picker (light)] + expected: FAIL + + [Property color value 'CanvasText' has the same color as the color of the html element (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a text field (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a text field (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a password field (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a password field (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a email field (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a email field (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a number field (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a number field (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a date field (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a date field (light)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a text area (light)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a text area (light)] + expected: FAIL + + [Property color value 'Mark' has the same color as the background-color of a mark element (light)] + expected: FAIL + + [Property color value 'MarkText' has the same color as the color of a mark element (light)] + expected: FAIL + + [Property color value 'LinkText' has the same color as the color of an anchor element (light)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a button (dark)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a button (dark)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a button (dark)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a submit button (dark)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a submit button (dark)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a submit button (dark)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a reset button (dark)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a reset button (dark)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a reset button (dark)] + expected: FAIL + + [Property color value 'ButtonBorder' resolves to the same color as the border-color of a color picker (dark)] + expected: FAIL + + [Property color value 'ButtonFace' resolves to the same color as the background-color of a color picker (dark)] + expected: FAIL + + [Property color value 'ButtonText' resolves to the same color as text on a color picker (dark)] + expected: FAIL + + [Property color value 'CanvasText' has the same color as the color of the html element (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a text field (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a text field (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a password field (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a password field (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a email field (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a email field (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a number field (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a number field (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a date field (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a date field (dark)] + expected: FAIL + + [Property color value 'Field' resolves to the same color as the background-color of a text area (dark)] + expected: FAIL + + [Property color value 'FieldText' resolves to the same color as text on a text area (dark)] + expected: FAIL + + [Property color value 'Mark' has the same color as the background-color of a mark element (dark)] + expected: FAIL + + [Property color value 'MarkText' has the same color as the color of a mark element (dark)] + expected: FAIL + + [Property color value 'LinkText' has the same color as the color of an anchor element (dark)] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-serialization-prevention.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-serialization-prevention.html.ini index de8c77a330a..4c4eee915bc 100644 --- a/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-serialization-prevention.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-serialization-prevention.html.ini @@ -67,3 +67,39 @@ [Setting font-stretch to normal should not prevent the font shorthand from serializing in computed style] expected: FAIL + + [Setting font-language-override to initial should prevent the font shorthand from serializing in specified style] + expected: FAIL + + [Setting font-language-override to initial should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to inherit should prevent the font shorthand from serializing in specified style] + expected: FAIL + + [Setting font-language-override to inherit should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to unset should prevent the font shorthand from serializing in specified style] + expected: FAIL + + [Setting font-language-override to unset should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to revert should prevent the font shorthand from serializing in specified style] + expected: FAIL + + [Setting font-language-override to revert should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to revert-layer should prevent the font shorthand from serializing in specified style] + expected: FAIL + + [Setting font-language-override to revert-layer should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to normal should not prevent the font shorthand from serializing in computed style] + expected: FAIL + + [Setting font-language-override to "SRB" should prevent the font shorthand from serializing in specified style] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-subproperties-reset.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-subproperties-reset.html.ini index 94c6da92bc6..5f677a7fdd1 100644 --- a/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-subproperties-reset.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-fonts/font-shorthand-subproperties-reset.html.ini @@ -1,2 +1,3 @@ [font-shorthand-subproperties-reset.html] - expected: TIMEOUT + [Property font-language-override should be reset to its initial value.] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/inheritance.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/inheritance.html.ini index 9e4c85353fa..21fa79019b9 100644 --- a/tests/wpt/meta-legacy-layout/css/css-fonts/inheritance.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-fonts/inheritance.html.ini @@ -62,9 +62,6 @@ [Property font-variant-alternates has initial value normal] expected: FAIL - [Property font-language-override inherits] - expected: FAIL - [Property font-optical-sizing has initial value auto] expected: FAIL @@ -74,9 +71,6 @@ [Property font-variant-alternates inherits] expected: FAIL - [Property font-language-override has initial value normal] - expected: FAIL - [Property font-synthesis has initial value weight style small-caps] expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-computed.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-computed.html.ini index a5edebe0490..62bcceb8d3b 100644 --- a/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-computed.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-computed.html.ini @@ -5,20 +5,5 @@ [Property font-language-override value 'normal' computes to 'normal'] expected: FAIL - [Property font-language-override value 'normal'] - expected: FAIL - [Property font-language-override value '"ksw"'] expected: FAIL - - [Property font-language-override value '"KSW"'] - expected: FAIL - - [Property font-language-override value '"ENG "'] - expected: FAIL - - [Property font-language-override value '"en "'] - expected: FAIL - - [Property font-language-override value '" en "'] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-valid.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-valid.html.ini deleted file mode 100644 index 13692267ac0..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-fonts/parsing/font-language-override-valid.html.ini +++ /dev/null @@ -1,27 +0,0 @@ -[font-language-override-valid.html] - [e.style['font-language-override'\] = "\\"ksw\\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "normal" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"KSW\\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"APPH\\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"ENG \\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"tr\\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"en \\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\" en \\"" should set the property value] - expected: FAIL - - [e.style['font-language-override'\] = "\\"1 %\\"" should set the property value] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-images/gradient/color-stops-parsing.html.ini b/tests/wpt/meta-legacy-layout/css/css-images/gradient/color-stops-parsing.html.ini deleted file mode 100644 index 5349947628e..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-images/gradient/color-stops-parsing.html.ini +++ /dev/null @@ -1,86 +0,0 @@ -[color-stops-parsing.html] - - [conic-gradient(black, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0%, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0%, white 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black, green, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0%, green 50%, white 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black 50%, green 10%, white 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black, 25%, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0%, 25%, white 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0%, 15%, green 50%, 60%, white 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0% 50%, white) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0% 50%, white 50% 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]] - expected: FAIL - - [conic-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0%, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0%, white 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black, green, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0%, green 50%, white 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 50%, green 10%, white 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black, 25%, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0%, 25%, white 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0%, 15%, green 50%, 60%, white 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0% 50%, white) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0% 50%, white 50% 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0% 50%, green 25% 75%, white 50% 100%) [ parsable \]] - expected: FAIL - - [repeating-conic-gradient(black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%) [ parsable \]] - expected: FAIL - diff --git a/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-computed.html.ini b/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-computed.html.ini index e874313f3f8..481d467be07 100644 --- a/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-computed.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-computed.html.ini @@ -1943,18 +1943,6 @@ [Property background-image value 'radial-gradient(in oklch decreasing hue at right center, color(srgb 1 0 0), blue)'] expected: FAIL - [Property background-image value 'conic-gradient(from 30deg, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(at left 10px top 50em, red, blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(from 30deg, color(srgb 1 0 0), blue)'] - expected: FAIL - - [Property background-image value 'conic-gradient(at left 10px top 50em, color(srgb 1 0 0), blue)'] - expected: FAIL - [Property background-image value 'conic-gradient(in lab, red, blue)'] expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-valid.html.ini b/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-valid.html.ini index 22e41992693..1dd3f6d54fa 100644 --- a/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-valid.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-images/parsing/gradient-interpolation-method-valid.html.ini @@ -1943,18 +1943,6 @@ [e.style['background-image'\] = "radial-gradient(in oklch decreasing hue at right center, color(srgb 1 0 0), blue)" should set the property value] expected: FAIL - [e.style['background-image'\] = "conic-gradient(from 30deg, red, blue)" should set the property value] - expected: FAIL - - [e.style['background-image'\] = "conic-gradient(at left 10px top 50em, red, blue)" should set the property value] - expected: FAIL - - [e.style['background-image'\] = "conic-gradient(from 30deg, color(srgb 1 0 0), blue)" should set the property value] - expected: FAIL - - [e.style['background-image'\] = "conic-gradient(at left 10px top 50em, color(srgb 1 0 0), blue)" should set the property value] - expected: FAIL - [e.style['background-image'\] = "conic-gradient(in lab, red, blue)" should set the property value] expected: FAIL @@ -3737,12 +3725,6 @@ [e.style['background-image'\] = "radial-gradient(in oklch decreasing hue at right center, red, 50%, blue)" should set the property value] expected: FAIL - [e.style['background-image'\] = "conic-gradient(from 30deg, red, 50%, blue)" should set the property value] - expected: FAIL - - [e.style['background-image'\] = "conic-gradient(at left 10px top 50em, red, 50%, blue)" should set the property value] - expected: FAIL - [e.style['background-image'\] = "conic-gradient(in lab, red, 50%, blue)" should set the property value] expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-pseudo/selection-background-color-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-pseudo/selection-background-color-001.html.ini new file mode 100644 index 00000000000..2ba2bb4894f --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-pseudo/selection-background-color-001.html.ini @@ -0,0 +1,2 @@ +[selection-background-color-001.html] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-text/parsing/webkit-text-stroke-computed.html.ini b/tests/wpt/meta-legacy-layout/css/css-text/parsing/webkit-text-stroke-computed.html.ini new file mode 100644 index 00000000000..6b4372771dd --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-text/parsing/webkit-text-stroke-computed.html.ini @@ -0,0 +1,9 @@ +[webkit-text-stroke-computed.html] + [Property -webkit-text-stroke value 'green'] + expected: FAIL + + [Property -webkit-text-stroke value '3px'] + expected: FAIL + + [Property -webkit-text-stroke value '1px red'] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-text/white-space/text-wrap-balance-003.html.ini b/tests/wpt/meta-legacy-layout/css/css-text/white-space/text-wrap-balance-003.html.ini new file mode 100644 index 00000000000..3a4f210bbf0 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-text/white-space/text-wrap-balance-003.html.ini @@ -0,0 +1,2 @@ +[text-wrap-balance-003.html] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/animation/rotate-interpolation-math-functions-tentative.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/animation/rotate-interpolation-math-functions-tentative.html.ini new file mode 100644 index 00000000000..ad1ee1284d2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-transforms/animation/rotate-interpolation-math-functions-tentative.html.ini @@ -0,0 +1,144 @@ +[rotate-interpolation-math-functions-tentative.html] + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Transitions: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [Web Animations: property from [100deg\] to [calc(sign(20rem - 20px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (-1) should be [20deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0) should be [100deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.125) should be [110deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (0.875) should be [170deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (1) should be [180deg\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100deg)\] to [calc(progress(10rem from 20px to 100px) * 180deg)\] at (2) should be [260deg\]] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/animation/scale-animation-math-functions-tentative.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/animation/scale-animation-math-functions-tentative.html.ini new file mode 100644 index 00000000000..1df3f824ee2 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-transforms/animation/scale-animation-math-functions-tentative.html.ini @@ -0,0 +1,144 @@ +[scale-animation-math-functions-tentative.html] + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Transitions: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [Web Animations: property from [100\] to [calc(sign(20rem - 20px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Transitions: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Transitions with transition: all: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [CSS Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (2) should be [260\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (-1) should be [20\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0) should be [100\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.125) should be [110\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (0.875) should be [170\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (1) should be [180\]] + expected: FAIL + + [Web Animations: property from [calc(sign(20rem - 20px) * 100)\] to [calc(progress(10rem from 20px to 100px) * 180)\] at (2) should be [260\]] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-above-001.xht.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-above-001.xht.ini deleted file mode 100644 index 9003e9cacf1..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-above-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[transform-3d-rotateY-stair-above-001.xht] - type: reftest - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-below-001.xht.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-below-001.xht.ini index 47c7cc7d9f9..298c8a60b79 100644 --- a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-below-001.xht.ini +++ b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-3d-rotateY-stair-below-001.xht.ini @@ -1,4 +1,3 @@ [transform-3d-rotateY-stair-below-001.xht] type: reftest - expected: FAIL bug: https://github.com/servo/webrender/issues/1776 diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-percent-008.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-percent-008.html.ini deleted file mode 100644 index c6ea32cb9dd..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-percent-008.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transform-percent-008.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-009.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-009.html.ini new file mode 100644 index 00000000000..c7c7903553a --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-009.html.ini @@ -0,0 +1,2 @@ +[transform-table-009.html] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-010.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-010.html.ini new file mode 100644 index 00000000000..7cd32fa5416 --- /dev/null +++ b/tests/wpt/meta-legacy-layout/css/css-transforms/transform-table-010.html.ini @@ -0,0 +1,2 @@ +[transform-table-010.html] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewX.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewX.html.ini deleted file mode 100644 index de21e149b17..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewX.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[transforms-skewX.html] - type: reftest - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewY.html.ini b/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewY.html.ini deleted file mode 100644 index 0b3638c8121..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-transforms/transforms-skewY.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[transforms-skewY.html] - type: reftest - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-linear-radial-conic-gradient-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-linear-radial-conic-gradient-001.html.ini deleted file mode 100644 index f32894f9178..00000000000 --- a/tests/wpt/meta-legacy-layout/css/css-values/calc-linear-radial-conic-gradient-001.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[calc-linear-radial-conic-gradient-001.html] - [testing background-image: conic-gradient(rgb(0, 128, 0) calc(50% + 10%), rgb(0, 0, 255) calc(60% + 20%))] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/calc-size-height.tentative.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/calc-size-height.tentative.html.ini index ba84cd6c00b..9a753b3a13b 100644 --- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/calc-size-height.tentative.html.ini +++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/calc-size-height.tentative.html.ini @@ -79,3 +79,12 @@ [resolved height for height in definite height container: calc-size(calc-size(min-content, 30px), 15em)] expected: FAIL + + [resolved height for height in definite height container: calc(12% + calc-size(any, 31%))] + expected: FAIL + + [resolved height for height in auto height container: calc-size(any, 31% + 12px)] + expected: FAIL + + [resolved height for height in definite height container: calc-size(any, 31% + 12px)] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/cssom-view/elementsFromPoint.html.ini b/tests/wpt/meta-legacy-layout/css/cssom-view/elementsFromPoint.html.ini index 44e1393786a..34b5e1caf47 100644 --- a/tests/wpt/meta-legacy-layout/css/cssom-view/elementsFromPoint.html.ini +++ b/tests/wpt/meta-legacy-layout/css/cssom-view/elementsFromPoint.html.ini @@ -6,3 +6,5 @@ [transformed element at x,y] expected: FAIL + [no hit target at x,y] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/cssom/style-sheet-interfaces-001.html.ini b/tests/wpt/meta-legacy-layout/css/cssom/style-sheet-interfaces-001.html.ini index 20bea8c9342..256fdbd5da1 100644 --- a/tests/wpt/meta-legacy-layout/css/cssom/style-sheet-interfaces-001.html.ini +++ b/tests/wpt/meta-legacy-layout/css/cssom/style-sheet-interfaces-001.html.ini @@ -11,6 +11,3 @@ [StyleSheet_property_values] expected: FAIL - - [disabled attribute getter/setter] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/css/filter-effects/filters-drop-shadow-003.html.ini b/tests/wpt/meta-legacy-layout/css/filter-effects/filters-drop-shadow-003.html.ini deleted file mode 100644 index 911a1dd84cb..00000000000 --- a/tests/wpt/meta-legacy-layout/css/filter-effects/filters-drop-shadow-003.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[filters-drop-shadow-003.html] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget-customized-builtins.html.ini b/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget-customized-builtins.html.ini deleted file mode 100644 index 61d65764ac3..00000000000 --- a/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget-customized-builtins.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[newtarget-customized-builtins.html] - [If prototype is not object (null), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (undefined), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (5), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (string), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget.html.ini b/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget.html.ini deleted file mode 100644 index 292c32aad7e..00000000000 --- a/tests/wpt/meta-legacy-layout/custom-elements/htmlconstructor/newtarget.html.ini +++ /dev/null @@ -1,28 +0,0 @@ -[newtarget.html] - [Custom Elements: [HTMLConstructor\] derives prototype from NewTarget] - expected: FAIL - - [If prototype is not object (string), derives the fallback from NewTarget's GetFunctionRealm (autonomous custom elements)] - expected: FAIL - - [If prototype is not object (null), derives the fallback from NewTarget's GetFunctionRealm (autonomous custom elements)] - expected: FAIL - - [If prototype is not object (undefined), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (undefined), derives the fallback from NewTarget's GetFunctionRealm (autonomous custom elements)] - expected: FAIL - - [If prototype is not object (5), derives the fallback from NewTarget's GetFunctionRealm (autonomous custom elements)] - expected: FAIL - - [If prototype is not object (string), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (5), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - - [If prototype is not object (null), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)] - expected: FAIL - diff --git a/tests/wpt/meta-legacy-layout/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html.ini b/tests/wpt/meta-legacy-layout/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html.ini new file mode 100644 index 00000000000..0d747763bda --- /dev/null +++ b/tests/wpt/meta-legacy-layout/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html.ini @@ -0,0 +1,3 @@ +[Node-append-meta-referrer-and-script-from-fragment.tentative.html] + [ should apply before script, as it is an insertion step and not a post-insertion step] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/fetch/api/basic/request-upload.h2.any.js.ini b/tests/wpt/meta-legacy-layout/fetch/api/basic/request-upload.h2.any.js.ini index 40f8cb45732..e039ea7fbfc 100644 --- a/tests/wpt/meta-legacy-layout/fetch/api/basic/request-upload.h2.any.js.ini +++ b/tests/wpt/meta-legacy-layout/fetch/api/basic/request-upload.h2.any.js.ini @@ -36,6 +36,9 @@ [Streaming upload should fail on a 401 response] expected: NOTRUN + [ReadbleStream should be closed on signal.abort] + expected: NOTRUN + [request-upload.h2.any.html] expected: TIMEOUT @@ -72,6 +75,9 @@ [Streaming upload should fail on a 401 response] expected: NOTRUN + [ReadbleStream should be closed on signal.abort] + expected: NOTRUN + [request-upload.h2.any.sharedworker.html] expected: ERROR diff --git a/tests/wpt/meta-legacy-layout/fetch/api/body/formdata.any.js.ini b/tests/wpt/meta-legacy-layout/fetch/api/body/formdata.any.js.ini index 2fbdce4291b..f70c16e0801 100644 --- a/tests/wpt/meta-legacy-layout/fetch/api/body/formdata.any.js.ini +++ b/tests/wpt/meta-legacy-layout/fetch/api/body/formdata.any.js.ini @@ -5,6 +5,9 @@ [Consume empty request.formData() as FormData] expected: FAIL + [Consume multipart/form-data headers case-insensitively] + expected: FAIL + [formdata.any.html] [Consume empty response.formData() as FormData] @@ -12,3 +15,6 @@ [Consume empty request.formData() as FormData] expected: FAIL + + [Consume multipart/form-data headers case-insensitively] + expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/gamepad/not-fully-active.html.ini b/tests/wpt/meta-legacy-layout/gamepad/not-fully-active.html.ini deleted file mode 100644 index 1b5a91a41e7..00000000000 --- a/tests/wpt/meta-legacy-layout/gamepad/not-fully-active.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[not-fully-active.html] - [calling getGamepads() in a non-fully-active document] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/empty-iframe-load-event.html.ini b/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/empty-iframe-load-event.html.ini deleted file mode 100644 index 3e07e6b7d1f..00000000000 --- a/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/empty-iframe-load-event.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[empty-iframe-load-event.html] - [Check execution order from nested timeout] - expected: FAIL - - [Check execution order on load handler] - expected: FAIL diff --git a/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html.ini b/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html.ini index 149bcb4ff8c..b8fd22e2b81 100644 --- a/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html.ini +++ b/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html.ini @@ -10,3 +10,6 @@ [load & pageshow events do not fire on contentWindow of + + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/assign-replace-from-top-to-nested-iframe.html b/tests/wpt/tests/html/browsers/history/the-location-interface/assign-replace-from-top-to-nested-iframe.html new file mode 100644 index 00000000000..eb6e4960dc2 --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/assign-replace-from-top-to-nested-iframe.html @@ -0,0 +1,36 @@ + + + + Referer with location.replace and location.assign with nested iframes + + + + + + + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/assign-with-nested-iframe.html b/tests/wpt/tests/html/browsers/history/the-location-interface/assign-with-nested-iframe.html new file mode 100644 index 00000000000..e043623c082 --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/assign-with-nested-iframe.html @@ -0,0 +1,21 @@ + + + + Referer with location.assign and nested frames + + + + + + + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/replace-with-nested-iframe.html b/tests/wpt/tests/html/browsers/history/the-location-interface/replace-with-nested-iframe.html new file mode 100644 index 00000000000..e6620bd29c7 --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/replace-with-nested-iframe.html @@ -0,0 +1,21 @@ + + + + Referer with location.replace and nested frames + + + + + + + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-contents.sub.html b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-contents.sub.html new file mode 100644 index 00000000000..8ac0a264dbc --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-contents.sub.html @@ -0,0 +1,14 @@ + + + + Resource file for test of Referer with location.replace + + +
+ + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-postmessage-to-parent-parent.sub.html b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-postmessage-to-parent-parent.sub.html new file mode 100644 index 00000000000..25c4af19a3e --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-postmessage-to-parent-parent.sub.html @@ -0,0 +1,14 @@ + + + + Resource file for test of Referer with location.replace + + +
+ + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-with-iframe.html b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-with-iframe.html new file mode 100644 index 00000000000..675f293ffa3 --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/iframe-with-iframe.html @@ -0,0 +1,9 @@ + + + + Resource file for test of Referer with location.replace and location.assign + + + + + diff --git a/tests/wpt/tests/html/browsers/history/the-location-interface/resources/replace-or-assign-call-on-iframe.html b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/replace-or-assign-call-on-iframe.html new file mode 100644 index 00000000000..bdad8334a5e --- /dev/null +++ b/tests/wpt/tests/html/browsers/history/the-location-interface/resources/replace-or-assign-call-on-iframe.html @@ -0,0 +1,20 @@ + + + + Referer with location.replace and location.assign + + + + + + diff --git a/tests/wpt/tests/html/canvas/element/drawing-images-to-the-canvas/2d.drawImage.detachedcanvas.html b/tests/wpt/tests/html/canvas/element/drawing-images-to-the-canvas/2d.drawImage.detachedcanvas.html new file mode 100644 index 00000000000..e301537330e --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/drawing-images-to-the-canvas/2d.drawImage.detachedcanvas.html @@ -0,0 +1,28 @@ + + +Canvas test: 2d.drawImage.detachedcanvas + + + + + + +

2d.drawImage.detachedcanvas

+

drawImage with detached OffscreenCanvas as the source should throw exception

+ + +

Actual output:

+

FAIL (fallback content)

+ +
    + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html index 42fb1ee8f84..dc947928676 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html @@ -8,7 +8,7 @@

    2d.filter.canvasFilterObject.blur.exceptions.tentative

    -

    Test exceptions on CanvasFilter() blur.object

    +

    Test exceptions on gaussianBlur filter

    Actual output:

    @@ -16,15 +16,21 @@
      diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.html index b2f6a6ac97e..56cf1bf0b1c 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.html @@ -8,7 +8,7 @@

      2d.filter.canvasFilterObject.colorMatrix.tentative

      -

      Test the functionality of ColorMatrix filters in CanvasFilter objects

      +

      Test the functionality of ColorMatrix filters

      Actual output:

      @@ -16,41 +16,70 @@
        diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html index b392b189f21..0a4830568b4 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html @@ -1,41 +1,16 @@ + + Canvas test: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative - - - - - -

        2d.filter.canvasFilterObject.componentTransfer.discrete.tentative

        Test pixels on CanvasFilter() componentTransfer with discrete type

        - - -

        Actual output:

        -

        FAIL (fallback content)

        - -
          + +

          FAIL (fallback content)

          +
          - diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html new file mode 100644 index 00000000000..5adc9f53e20 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative +

          2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

          +

          Test pixels on CanvasFilter() componentTransfer with gamma type

          + +

          FAIL (fallback content)

          +
          + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html index e5bff7e44df..22e3abe624f 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html @@ -1,40 +1,27 @@ + + Canvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative - - - - - -

          2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

          Test pixels on CanvasFilter() componentTransfer with gamma type

          - - -

          Actual output:

          -

          FAIL (fallback content)

          - -
            + +

            FAIL (fallback content)

            +
            - diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html new file mode 100644 index 00000000000..895d531206c --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html @@ -0,0 +1,27 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative +

            2d.filter.canvasFilterObject.componentTransfer.identity.tentative

            +

            Test pixels on CanvasFilter() componentTransfer with identity type

            + +

            FAIL (fallback content)

            +
            + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html index ecd3830be3e..17761ce31a2 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html @@ -1,23 +1,15 @@ + Canvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative - - - - - -

            2d.filter.canvasFilterObject.componentTransfer.identity.tentative

            Test pixels on CanvasFilter() componentTransfer with identity type

            - - -

            Actual output:

            -

            FAIL (fallback content)

            - -
              + +

              FAIL (fallback content)

              +
              - diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html new file mode 100644 index 00000000000..c4ad790d56e --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html @@ -0,0 +1,43 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative +

              2d.filter.canvasFilterObject.componentTransfer.linear.tentative

              +

              Test pixels on CanvasFilter() componentTransfer with linear type

              + +

              FAIL (fallback content)

              +
              + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html index 8708887f6a5..5ea5f8e0e31 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html @@ -1,32 +1,16 @@ + + Canvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative - - - - - -

              2d.filter.canvasFilterObject.componentTransfer.linear.tentative

              Test pixels on CanvasFilter() componentTransfer with linear type

              - - -

              Actual output:

              -

              FAIL (fallback content)

              - -
                + +

                FAIL (fallback content)

                +
                - diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html new file mode 100644 index 00000000000..29e250614c2 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html @@ -0,0 +1,51 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative +

                2d.filter.canvasFilterObject.componentTransfer.table.tentative

                +

                Test pixels on CanvasFilter() componentTransfer with table type

                + +

                FAIL (fallback content)

                +
                + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html index 4b296d9fd7d..0f74d9c3bfd 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html @@ -1,41 +1,16 @@ + + Canvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative - - - - - -

                2d.filter.canvasFilterObject.componentTransfer.table.tentative

                Test pixels on CanvasFilter() componentTransfer with table type

                - - -

                Actual output:

                -

                FAIL (fallback content)

                - -
                  + +

                  FAIL (fallback content)

                  +
                  - diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html index b80600c1417..a2885410570 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html @@ -19,23 +19,39 @@ var t = async_test("Test exceptions on CanvasFilter() convolveMatrix"); _addTest(function(canvas, ctx) { - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', divisor: 2}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: 1}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: []}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', divisor: 2}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: 1}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: []}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); // This should not throw an error - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[]]}); - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1]]}); }); diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html index 8c07a72b2b3..05984a47f82 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html @@ -19,104 +19,250 @@ var t = async_test("Test exceptions on CanvasFilter() dropShadow object"); _addTest(function(canvas, ctx) { + // Should not throw an error. // dx - _assert(new CanvasFilter({name: 'dropShadow', dx: 10}), "new CanvasFilter({name: 'dropShadow', dx: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: -1}), "new CanvasFilter({name: 'dropShadow', dx: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: 0.5}), "new CanvasFilter({name: 'dropShadow', dx: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: null}), "new CanvasFilter({name: 'dropShadow', dx: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: true}), "new CanvasFilter({name: 'dropShadow', dx: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: false}), "new CanvasFilter({name: 'dropShadow', dx: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: []}), "new CanvasFilter({name: 'dropShadow', dx: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: [20]}), "new CanvasFilter({name: 'dropShadow', dx: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: '30'}), "new CanvasFilter({name: 'dropShadow', dx: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); // dy - _assert(new CanvasFilter({name: 'dropShadow', dy: 10}), "new CanvasFilter({name: 'dropShadow', dy: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: -1}), "new CanvasFilter({name: 'dropShadow', dy: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: 0.5}), "new CanvasFilter({name: 'dropShadow', dy: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: null}), "new CanvasFilter({name: 'dropShadow', dy: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: true}), "new CanvasFilter({name: 'dropShadow', dy: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: false}), "new CanvasFilter({name: 'dropShadow', dy: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: []}), "new CanvasFilter({name: 'dropShadow', dy: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: [20]}), "new CanvasFilter({name: 'dropShadow', dy: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: '30'}), "new CanvasFilter({name: 'dropShadow', dy: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); // floodOpacity - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 10}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: -1}), "new CanvasFilter({name: 'dropShadow', floodOpacity: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: null}), "new CanvasFilter({name: 'dropShadow', floodOpacity: null})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: true}), "new CanvasFilter({name: 'dropShadow', floodOpacity: true})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: false}), "new CanvasFilter({name: 'dropShadow', floodOpacity: false})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: []}), "new CanvasFilter({name: 'dropShadow', floodOpacity: []})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: [20]}), "new CanvasFilter({name: 'dropShadow', floodOpacity: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: '30'}), "new CanvasFilter({name: 'dropShadow', floodOpacity: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); + // dx + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); + // dy + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); + // floodOpacity + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); // stdDeviation - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 10}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: -1}), "new CanvasFilter({name: 'dropShadow', stdDeviation: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: null}), "new CanvasFilter({name: 'dropShadow', stdDeviation: null})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: true}), "new CanvasFilter({name: 'dropShadow', stdDeviation: true})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: false}), "new CanvasFilter({name: 'dropShadow', stdDeviation: false})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: []}), "new CanvasFilter({name: 'dropShadow', stdDeviation: []})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [20]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: '30'}), "new CanvasFilter({name: 'dropShadow', stdDeviation: '30'})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [20]]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [\""+(20)+"\"]]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: '30'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [10, -1]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [0.5, null]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [true, false]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [[], [20]]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: ['30', ['40']]}); // floodColor - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'red'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'red'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'red'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'canvas'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#aabbccdd'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#abcd'}); + // Should throw a TypeError. // dx - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [1, 2]}); }); // dy - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [1, 2]}); }); // floodOpacity - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [1, 2]}); }); // stdDeviation - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, NaN]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, undefined]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 'test']}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, {}]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, NaN]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, undefined]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 'test']}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, {}]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); // floodColor - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 10}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 10}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: NaN}); }); }); diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html index 47bb891b3f8..d6e70664738 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html @@ -22,86 +22,58 @@ // Parameter defaults. ctx.filter = new CanvasFilter({name: 'dropShadow'}); ctx.fillRect(10, 10, 80, 80); - // All parameters specified. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple', floodOpacity: 0.7}); ctx.fillRect(110, 10, 80, 80); - // Named color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'purple'}); ctx.fillRect(10, 110, 80, 80); - // System color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'LinkText'}); ctx.fillRect(110, 110, 80, 80); - // Numerical color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 1)'}); ctx.fillRect(210, 110, 80, 80); - // Transparent floodColor. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)'}); ctx.fillRect(310, 110, 80, 80); - // Transparent floodColor and floodOpacity. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}); ctx.fillRect(410, 110, 80, 80); - // No blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, floodColor: 'purple'}); ctx.fillRect(10, 210, 80, 80); - // Single float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple'}); ctx.fillRect(110, 210, 80, 80); - // Single negative float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, floodColor: 'purple'}); ctx.fillRect(210, 210, 80, 80); - // Two floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], floodColor: 'purple'}); ctx.fillRect(310, 210, 80, 80); - // Two negative floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], floodColor: 'purple'}); ctx.fillRect(410, 210, 80, 80); - // Degenerate parameter values. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, floodColor: 'purple', floodOpacity: [2]}); ctx.fillRect(10, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], floodColor: 'purple', floodOpacity: '0.8'}); ctx.fillRect(110, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, floodColor: 'purple', floodOpacity: ['0.4']}); ctx.fillRect(210, 310, 80, 80); diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html index c24cfd23981..b85add4b664 100644 --- a/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html @@ -116,12 +116,12 @@ _addTest(function(canvas, ctx) { for (testCase of errorTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - assert_throws_js(TypeError, function() { new CanvasFilter(filterOptions); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter(filterOptions); }); } for (testCase of workingTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - _assert(new CanvasFilter(filterOptions) != null, "new CanvasFilter(filterOptions) != null"); + ctx.filter = new CanvasFilter(filterOptions); } }); diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.blur.exceptions.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.blur.exceptions.html new file mode 100644 index 00000000000..7176a7d0a48 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.blur.exceptions.html @@ -0,0 +1,37 @@ + + +Canvas test: 2d.filter.layers.blur.exceptions + + + + + + +

                  2d.filter.layers.blur.exceptions

                  +

                  Test exceptions on gaussianBlur filter

                  + + +

                  Actual output:

                  +

                  FAIL (fallback content)

                  + +
                    + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.colorMatrix.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.colorMatrix.html new file mode 100644 index 00000000000..ef0ae0f949b --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.colorMatrix.html @@ -0,0 +1,104 @@ + + +Canvas test: 2d.filter.layers.colorMatrix + + + + + + +

                    2d.filter.layers.colorMatrix

                    +

                    Test the functionality of ColorMatrix filters

                    + + +

                    Actual output:

                    +

                    FAIL (fallback content)

                    + +
                      + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete-expected.html new file mode 100644 index 00000000000..8419953b3d2 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete-expected.html @@ -0,0 +1,50 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.discrete +

                      2d.filter.layers.componentTransfer.discrete

                      +

                      Test pixels on CanvasFilter() componentTransfer with discrete type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete.html new file mode 100644 index 00000000000..ef9db79547c --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.discrete.html @@ -0,0 +1,38 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.discrete +

                      2d.filter.layers.componentTransfer.discrete

                      +

                      Test pixels on CanvasFilter() componentTransfer with discrete type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma-expected.html new file mode 100644 index 00000000000..3e5d9808967 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.gamma +

                      2d.filter.layers.componentTransfer.gamma

                      +

                      Test pixels on CanvasFilter() componentTransfer with gamma type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma.html new file mode 100644 index 00000000000..cccd07e92b9 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.gamma.html @@ -0,0 +1,41 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.gamma +

                      2d.filter.layers.componentTransfer.gamma

                      +

                      Test pixels on CanvasFilter() componentTransfer with gamma type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity-expected.html new file mode 100644 index 00000000000..9f1439f37b6 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity-expected.html @@ -0,0 +1,27 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.identity +

                      2d.filter.layers.componentTransfer.identity

                      +

                      Test pixels on CanvasFilter() componentTransfer with identity type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity.html new file mode 100644 index 00000000000..3a06353849c --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.identity.html @@ -0,0 +1,34 @@ + + + +Canvas test: 2d.filter.layers.componentTransfer.identity +

                      2d.filter.layers.componentTransfer.identity

                      +

                      Test pixels on CanvasFilter() componentTransfer with identity type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear-expected.html new file mode 100644 index 00000000000..f922055ff26 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.linear +

                      2d.filter.layers.componentTransfer.linear

                      +

                      Test pixels on CanvasFilter() componentTransfer with linear type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear.html new file mode 100644 index 00000000000..c9e744ebef0 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.linear.html @@ -0,0 +1,37 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.linear +

                      2d.filter.layers.componentTransfer.linear

                      +

                      Test pixels on CanvasFilter() componentTransfer with linear type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table-expected.html new file mode 100644 index 00000000000..0f6736d87d4 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table-expected.html @@ -0,0 +1,51 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.table +

                      2d.filter.layers.componentTransfer.table

                      +

                      Test pixels on CanvasFilter() componentTransfer with table type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table.html new file mode 100644 index 00000000000..eae036b142d --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.componentTransfer.table.html @@ -0,0 +1,38 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.table +

                      2d.filter.layers.componentTransfer.table

                      +

                      Test pixels on CanvasFilter() componentTransfer with table type

                      + +

                      FAIL (fallback content)

                      +
                      + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.convolveMatrix.exceptions.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.convolveMatrix.exceptions.html new file mode 100644 index 00000000000..ae45cb865c5 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.convolveMatrix.exceptions.html @@ -0,0 +1,60 @@ + + +Canvas test: 2d.filter.layers.convolveMatrix.exceptions + + + + + + +

                      2d.filter.layers.convolveMatrix.exceptions

                      +

                      Test exceptions on CanvasFilter() convolveMatrix

                      + + +

                      Actual output:

                      +

                      FAIL (fallback content)

                      + +
                        + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow-expected.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow-expected.html new file mode 100644 index 00000000000..1719d99b4a7 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow-expected.html @@ -0,0 +1,57 @@ + + +Canvas test: 2d.filter.layers.dropShadow +

                        2d.filter.layers.dropShadow

                        +

                        Test CanvasFilter() dropShadow object.

                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.exceptions.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.exceptions.html new file mode 100644 index 00000000000..df5e0c7dc3e --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.exceptions.html @@ -0,0 +1,269 @@ + + +Canvas test: 2d.filter.layers.dropShadow.exceptions + + + + + + +

                        2d.filter.layers.dropShadow.exceptions

                        +

                        Test exceptions on CanvasFilter() dropShadow object

                        + + +

                        Actual output:

                        +

                        FAIL (fallback content)

                        + +
                          + + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.html new file mode 100644 index 00000000000..ceb20bb9eb3 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.dropShadow.html @@ -0,0 +1,94 @@ + + + +Canvas test: 2d.filter.layers.dropShadow +

                          2d.filter.layers.dropShadow

                          +

                          Test CanvasFilter() dropShadow object.

                          + +

                          FAIL (fallback content)

                          +
                          + diff --git a/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.turbulence.inputTypes.html b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.turbulence.inputTypes.html new file mode 100644 index 00000000000..26dceaae165 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/filters/2d.filter.layers.turbulence.inputTypes.html @@ -0,0 +1,130 @@ + + +Canvas test: 2d.filter.layers.turbulence.inputTypes + + + + + + +

                          2d.filter.layers.turbulence.inputTypes

                          +

                          Test exceptions on CanvasFilter() turbulence object

                          + + +

                          Actual output:

                          +

                          FAIL (fallback content)

                          + +
                            + + diff --git a/tests/wpt/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html b/tests/wpt/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html index 27989c79e93..98ea67e9e96 100644 --- a/tests/wpt/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html +++ b/tests/wpt/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html @@ -1,7 +1,7 @@ - + Canvas test: 2d.layer.global-states.filter.alpha.blending

                            2d.layer.global-states.filter.alpha.blending

                            Checks that layers with filters correctly use global render states.

                            diff --git a/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html b/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html new file mode 100644 index 00000000000..a76c49d2d47 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html @@ -0,0 +1,26 @@ + + +Canvas test: 2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https + + + + + + +

                            2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https

                            +

                            getTextureFormat() returns RGBA16F for a float16 context

                            + + +

                            Actual output:

                            +

                            FAIL (fallback content)

                            + +
                              + + diff --git a/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html b/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html new file mode 100644 index 00000000000..ef576133742 --- /dev/null +++ b/tests/wpt/tests/html/canvas/element/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html @@ -0,0 +1,26 @@ + + +Canvas test: 2d.webgpuaccess.getTextureFormat.rgba8.tentative.https + + + + + + +

                              2d.webgpuaccess.getTextureFormat.rgba8.tentative.https

                              +

                              getTextureFormat() returns RGBA8 or BGRA8 for a typical context

                              + + +

                              Actual output:

                              +

                              FAIL (fallback content)

                              + +
                                + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html index d8f14529c53..e7461eacdbd 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.html @@ -6,11 +6,11 @@

                                2d.filter.canvasFilterObject.blur.exceptions.tentative

                                -

                                Test exceptions on CanvasFilter() blur.object

                                +

                                Test exceptions on gaussianBlur filter

                                2d.filter.canvasFilterObject.colorMatrix.tentative

                                -

                                Test the functionality of ColorMatrix filters in CanvasFilter objects

                                +

                                Test the functionality of ColorMatrix filters

                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html index ff1de6bc9cf..491d073efbc 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html @@ -1,42 +1,16 @@ -OffscreenCanvas test: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative - - - - + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative

                                2d.filter.canvasFilterObject.componentTransfer.discrete.tentative

                                Test pixels on CanvasFilter() componentTransfer with discrete type

                                - - + +

                                FAIL (fallback content)

                                +
                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.w.html new file mode 100644 index 00000000000..d3a999a2426 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.w.html @@ -0,0 +1,54 @@ + + + + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.discrete.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with discrete type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.js deleted file mode 100644 index 0e68f4899fe..00000000000 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.js +++ /dev/null @@ -1,62 +0,0 @@ -// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.componentTransfer.discrete.tentative -// Description:Test pixels on CanvasFilter() componentTransfer with discrete type -// Note: - -importScripts("/resources/testharness.js"); -importScripts("/html/canvas/resources/canvas-tests.js"); - -var t = async_test("Test pixels on CanvasFilter() componentTransfer with discrete type"); -var t_pass = t.done.bind(t); -var t_fail = t.step_func(function(reason) { - throw reason; -}); -t.step(function() { - - var canvas = new OffscreenCanvas(100, 50); - var ctx = canvas.getContext('2d'); - - // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement - function getTransformedValue(C, V) { - // Get the right interval - const n = V.length; - const k = C == 1 ? n - 1 : Math.floor(C * n); - return V[k]; - } - - function getColor(inputColor, tableValues) { - const result = [0, 0, 0]; - for (const i in inputColor) { - const C = inputColor[i]/255; - const Cprime = getTransformedValue(C, tableValues[i]); - result[i] = Math.max(0, Math.min(1, Cprime)) * 255; - } - return result; - } - - tableValuesR = [0, 0, 1, 1]; - tableValuesG = [2, 0, 0.5, 3]; - tableValuesB = [1, -1, 5, 0]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'discrete', tableValues: tableValuesR}, - funcG: {type: 'discrete', tableValues: tableValuesG}, - funcB: {type: 'discrete', tableValues: tableValuesB}, - }); - - const inputColors = [ - [255, 255, 255], - [0, 0, 0], - [127, 0, 34], - [252, 186, 3], - [50, 68, 87], - ]; - - for (const color of inputColors) { - let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); - } - t.done(); -}); -done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html new file mode 100644 index 00000000000..5adc9f53e20 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html index 64c30fc4177..b262f3b1d32 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html @@ -1,41 +1,27 @@ -OffscreenCanvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative - - - - + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

                                2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                - - + +

                                FAIL (fallback content)

                                +
                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.w.html new file mode 100644 index 00000000000..1fe346eacf2 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.w.html @@ -0,0 +1,57 @@ + + + + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.gamma.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.js deleted file mode 100644 index d59bc699df9..00000000000 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.js +++ /dev/null @@ -1,53 +0,0 @@ -// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.componentTransfer.gamma.tentative -// Description:Test pixels on CanvasFilter() componentTransfer with gamma type -// Note: - -importScripts("/resources/testharness.js"); -importScripts("/html/canvas/resources/canvas-tests.js"); - -var t = async_test("Test pixels on CanvasFilter() componentTransfer with gamma type"); -var t_pass = t.done.bind(t); -var t_fail = t.step_func(function(reason) { - throw reason; -}); -t.step(function() { - - var canvas = new OffscreenCanvas(100, 50); - var ctx = canvas.getContext('2d'); - - // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement - function getColor(inputColor, amplitude, exponent, offset) { - return [ - Math.max(0, Math.min(1, Math.pow(inputColor[0]/255, exponent[0]) * amplitude[0] + offset[0])) * 255, - Math.max(0, Math.min(1, Math.pow(inputColor[1]/255, exponent[1]) * amplitude[1] + offset[1])) * 255, - Math.max(0, Math.min(1, Math.pow(inputColor[2]/255, exponent[2]) * amplitude[2] + offset[2])) * 255, - ]; - } - - const amplitudes = [2, 1.1, 0.5]; - const exponents = [5, 3, 1]; - const offsets = [0.25, 0, 0.5]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'gamma', amplitude: amplitudes[0], exponent: exponents[0], offset: offsets[0]}, - funcG: {type: 'gamma', amplitude: amplitudes[1], exponent: exponents[1], offset: offsets[1]}, - funcB: {type: 'gamma', amplitude: amplitudes[2], exponent: exponents[2], offset: offsets[2]}, - }); - - const inputColors = [ - [255, 255, 255], - [0, 0, 0], - [127, 0, 34], - [252, 186, 3], - [50, 68, 87], - ]; - - for (const color of inputColors) { - let outputColor = getColor(color, amplitudes, exponents, offsets); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); - } - t.done(); -}); -done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html new file mode 100644 index 00000000000..895d531206c --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative-expected.html @@ -0,0 +1,27 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.identity.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html index e0d628952e0..26b6e4c7022 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html @@ -1,24 +1,15 @@ -OffscreenCanvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative - - - - + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative

                                2d.filter.canvasFilterObject.componentTransfer.identity.tentative

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                - - + +

                                FAIL (fallback content)

                                +
                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.w.html new file mode 100644 index 00000000000..d2216d16479 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.w.html @@ -0,0 +1,50 @@ + + + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.identity.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.js deleted file mode 100644 index 1b714b58ff7..00000000000 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.js +++ /dev/null @@ -1,40 +0,0 @@ -// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.componentTransfer.identity.tentative -// Description:Test pixels on CanvasFilter() componentTransfer with identity type -// Note: - -importScripts("/resources/testharness.js"); -importScripts("/html/canvas/resources/canvas-tests.js"); - -var t = async_test("Test pixels on CanvasFilter() componentTransfer with identity type"); -var t_pass = t.done.bind(t); -var t_fail = t.step_func(function(reason) { - throw reason; -}); -t.step(function() { - - var canvas = new OffscreenCanvas(100, 50); - var ctx = canvas.getContext('2d'); - - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'identity'}, - funcG: {type: 'identity'}, - funcB: {type: 'identity'}, - }); - - const inputColors = [ - [255, 255, 255], - [0, 0, 0], - [127, 0, 34], - [252, 186, 3], - [50, 68, 87], - ]; - - for (const color of inputColors) { - ctx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, 1)`, - ctx.fillRect(0, 0, 10, 10); - _assertPixel(canvas, 5, 5, color[0],color[1],color[2],255); - } - t.done(); -}); -done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html new file mode 100644 index 00000000000..c4ad790d56e --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative-expected.html @@ -0,0 +1,43 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.linear.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html index adbe557fd96..3fc3bd9eec2 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html @@ -1,33 +1,16 @@ -OffscreenCanvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative - - - - + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative

                                2d.filter.canvasFilterObject.componentTransfer.linear.tentative

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                - - + +

                                FAIL (fallback content)

                                +
                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.w.html new file mode 100644 index 00000000000..054dbce9299 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.w.html @@ -0,0 +1,53 @@ + + + + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.linear.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.js deleted file mode 100644 index fb2e01876fc..00000000000 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.js +++ /dev/null @@ -1,52 +0,0 @@ -// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.componentTransfer.linear.tentative -// Description:Test pixels on CanvasFilter() componentTransfer with linear type -// Note: - -importScripts("/resources/testharness.js"); -importScripts("/html/canvas/resources/canvas-tests.js"); - -var t = async_test("Test pixels on CanvasFilter() componentTransfer with linear type"); -var t_pass = t.done.bind(t); -var t_fail = t.step_func(function(reason) { - throw reason; -}); -t.step(function() { - - var canvas = new OffscreenCanvas(100, 50); - var ctx = canvas.getContext('2d'); - - // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement - function getColor(inputColor, slopes, intercepts) { - return [ - Math.max(0, Math.min(1, inputColor[0]/255 * slopes[0] + intercepts[0])) * 255, - Math.max(0, Math.min(1, inputColor[1]/255 * slopes[1] + intercepts[1])) * 255, - Math.max(0, Math.min(1, inputColor[2]/255 * slopes[2] + intercepts[2])) * 255, - ]; - } - - const slopes = [0.5, 1.2, -0.2]; - const intercepts = [0.25, 0, 0.5]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'linear', slope: slopes[0], intercept: intercepts[0]}, - funcG: {type: 'linear', slope: slopes[1], intercept: intercepts[1]}, - funcB: {type: 'linear', slope: slopes[2], intercept: intercepts[2]}, - }); - - const inputColors = [ - [255, 255, 255], - [0, 0, 0], - [127, 0, 34], - [252, 186, 3], - [50, 68, 87], - ]; - - for (const color of inputColors) { - let outputColor = getColor(color, slopes, intercepts); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); - } - t.done(); -}); -done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html new file mode 100644 index 00000000000..29e250614c2 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative-expected.html @@ -0,0 +1,51 @@ + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.table.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with table type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html index 47048b68a14..ef2da126eb4 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.html @@ -1,42 +1,16 @@ -OffscreenCanvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative - - - - + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative

                                2d.filter.canvasFilterObject.componentTransfer.table.tentative

                                Test pixels on CanvasFilter() componentTransfer with table type

                                - - + +

                                FAIL (fallback content)

                                +
                                diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.w.html new file mode 100644 index 00000000000..f39723da8e8 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.w.html @@ -0,0 +1,54 @@ + + + + + +Canvas test: 2d.filter.canvasFilterObject.componentTransfer.table.tentative +

                                2d.filter.canvasFilterObject.componentTransfer.table.tentative

                                +

                                Test pixels on CanvasFilter() componentTransfer with table type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.js deleted file mode 100644 index 0799e73a583..00000000000 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.js +++ /dev/null @@ -1,62 +0,0 @@ -// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.componentTransfer.table.tentative -// Description:Test pixels on CanvasFilter() componentTransfer with table type -// Note: - -importScripts("/resources/testharness.js"); -importScripts("/html/canvas/resources/canvas-tests.js"); - -var t = async_test("Test pixels on CanvasFilter() componentTransfer with table type"); -var t_pass = t.done.bind(t); -var t_fail = t.step_func(function(reason) { - throw reason; -}); -t.step(function() { - - var canvas = new OffscreenCanvas(100, 50); - var ctx = canvas.getContext('2d'); - - // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement - function getTransformedValue(C, V) { - // Get the right interval - const n = V.length - 1; - const k = C == 1 ? n - 1 : Math.floor(C * n); - return V[k] + (C - k/n) * n * (V[k + 1] - V[k]); - } - - function getColor(inputColor, tableValues) { - const result = [0, 0, 0]; - for (const i in inputColor) { - const C = inputColor[i]/255; - const Cprime = getTransformedValue(C, tableValues[i]); - result[i] = Math.max(0, Math.min(1, Cprime)) * 255; - } - return result; - } - - tableValuesR = [0, 0, 1, 1]; - tableValuesG = [2, 0, 0.5, 3]; - tableValuesB = [1, -1, 5, 0]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'table', tableValues: tableValuesR}, - funcG: {type: 'table', tableValues: tableValuesG}, - funcB: {type: 'table', tableValues: tableValuesB}, - }); - - const inputColors = [ - [255, 255, 255], - [0, 0, 0], - [127, 0, 34], - [252, 186, 3], - [50, 68, 87], - ]; - - for (const color of inputColors) { - let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); - } - t.done(); -}); -done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html index 301d11f888c..08f8860e998 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html @@ -20,23 +20,39 @@ t.step(function() { var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', divisor: 2}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: 1}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: []}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', divisor: 2}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: 1}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: []}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); // This should not throw an error - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[]]}); - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1]]}); t.done(); }); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.js index b4ce4d76b24..105ed67a758 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.js +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.js @@ -16,23 +16,39 @@ t.step(function() { var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', divisor: 2}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: 1}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: []}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', divisor: 2}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: 1}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: []}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); }); // This should not throw an error - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[]]}); - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[]]}); + ctx.filter = new CanvasFilter( + {name: 'convolveMatrix', kernelMatrix: [[1]]}); t.done(); }); done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html index 3e55e97e54f..cdd501ba8e9 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.html @@ -20,104 +20,250 @@ t.step(function() { var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); + // Should not throw an error. // dx - _assert(new CanvasFilter({name: 'dropShadow', dx: 10}), "new CanvasFilter({name: 'dropShadow', dx: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: -1}), "new CanvasFilter({name: 'dropShadow', dx: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: 0.5}), "new CanvasFilter({name: 'dropShadow', dx: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: null}), "new CanvasFilter({name: 'dropShadow', dx: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: true}), "new CanvasFilter({name: 'dropShadow', dx: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: false}), "new CanvasFilter({name: 'dropShadow', dx: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: []}), "new CanvasFilter({name: 'dropShadow', dx: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: [20]}), "new CanvasFilter({name: 'dropShadow', dx: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: '30'}), "new CanvasFilter({name: 'dropShadow', dx: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); // dy - _assert(new CanvasFilter({name: 'dropShadow', dy: 10}), "new CanvasFilter({name: 'dropShadow', dy: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: -1}), "new CanvasFilter({name: 'dropShadow', dy: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: 0.5}), "new CanvasFilter({name: 'dropShadow', dy: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: null}), "new CanvasFilter({name: 'dropShadow', dy: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: true}), "new CanvasFilter({name: 'dropShadow', dy: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: false}), "new CanvasFilter({name: 'dropShadow', dy: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: []}), "new CanvasFilter({name: 'dropShadow', dy: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: [20]}), "new CanvasFilter({name: 'dropShadow', dy: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: '30'}), "new CanvasFilter({name: 'dropShadow', dy: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); // floodOpacity - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 10}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: -1}), "new CanvasFilter({name: 'dropShadow', floodOpacity: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: null}), "new CanvasFilter({name: 'dropShadow', floodOpacity: null})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: true}), "new CanvasFilter({name: 'dropShadow', floodOpacity: true})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: false}), "new CanvasFilter({name: 'dropShadow', floodOpacity: false})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: []}), "new CanvasFilter({name: 'dropShadow', floodOpacity: []})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: [20]}), "new CanvasFilter({name: 'dropShadow', floodOpacity: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: '30'}), "new CanvasFilter({name: 'dropShadow', floodOpacity: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); + // dx + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); + // dy + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); + // floodOpacity + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); // stdDeviation - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 10}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: -1}), "new CanvasFilter({name: 'dropShadow', stdDeviation: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: null}), "new CanvasFilter({name: 'dropShadow', stdDeviation: null})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: true}), "new CanvasFilter({name: 'dropShadow', stdDeviation: true})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: false}), "new CanvasFilter({name: 'dropShadow', stdDeviation: false})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: []}), "new CanvasFilter({name: 'dropShadow', stdDeviation: []})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [20]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: '30'}), "new CanvasFilter({name: 'dropShadow', stdDeviation: '30'})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [20]]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [\""+(20)+"\"]]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: '30'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [10, -1]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [0.5, null]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [true, false]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [[], [20]]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: ['30', ['40']]}); // floodColor - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'red'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'red'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'red'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'canvas'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#aabbccdd'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#abcd'}); + // Should throw a TypeError. // dx - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [1, 2]}); }); // dy - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [1, 2]}); }); // floodOpacity - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [1, 2]}); }); // stdDeviation - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, NaN]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, undefined]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 'test']}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, {}]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, NaN]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, undefined]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 'test']}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, {}]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); // floodColor - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 10}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 10}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: NaN}); }); t.done(); }); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.worker.js index bd18524f28b..1d56865e687 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.worker.js +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.exceptions.tentative.worker.js @@ -16,104 +16,250 @@ t.step(function() { var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); + // Should not throw an error. // dx - _assert(new CanvasFilter({name: 'dropShadow', dx: 10}), "new CanvasFilter({name: 'dropShadow', dx: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: -1}), "new CanvasFilter({name: 'dropShadow', dx: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: 0.5}), "new CanvasFilter({name: 'dropShadow', dx: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: null}), "new CanvasFilter({name: 'dropShadow', dx: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: true}), "new CanvasFilter({name: 'dropShadow', dx: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: false}), "new CanvasFilter({name: 'dropShadow', dx: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: []}), "new CanvasFilter({name: 'dropShadow', dx: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: [20]}), "new CanvasFilter({name: 'dropShadow', dx: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dx: '30'}), "new CanvasFilter({name: 'dropShadow', dx: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); // dy - _assert(new CanvasFilter({name: 'dropShadow', dy: 10}), "new CanvasFilter({name: 'dropShadow', dy: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: -1}), "new CanvasFilter({name: 'dropShadow', dy: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: 0.5}), "new CanvasFilter({name: 'dropShadow', dy: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: null}), "new CanvasFilter({name: 'dropShadow', dy: null})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: true}), "new CanvasFilter({name: 'dropShadow', dy: true})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: false}), "new CanvasFilter({name: 'dropShadow', dy: false})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: []}), "new CanvasFilter({name: 'dropShadow', dy: []})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: [20]}), "new CanvasFilter({name: 'dropShadow', dy: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', dy: '30'}), "new CanvasFilter({name: 'dropShadow', dy: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); // floodOpacity - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 10}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: -1}), "new CanvasFilter({name: 'dropShadow', floodOpacity: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5}), "new CanvasFilter({name: 'dropShadow', floodOpacity: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: null}), "new CanvasFilter({name: 'dropShadow', floodOpacity: null})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: true}), "new CanvasFilter({name: 'dropShadow', floodOpacity: true})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: false}), "new CanvasFilter({name: 'dropShadow', floodOpacity: false})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: []}), "new CanvasFilter({name: 'dropShadow', floodOpacity: []})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: [20]}), "new CanvasFilter({name: 'dropShadow', floodOpacity: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', floodOpacity: '30'}), "new CanvasFilter({name: 'dropShadow', floodOpacity: '30'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); + // dx + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: '30'}); + // dy + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: '30'}); + // floodOpacity + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: '30'}); // stdDeviation - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 10}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 10})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: -1}), "new CanvasFilter({name: 'dropShadow', stdDeviation: -1})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5}), "new CanvasFilter({name: 'dropShadow', stdDeviation: 0.5})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: null}), "new CanvasFilter({name: 'dropShadow', stdDeviation: null})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: true}), "new CanvasFilter({name: 'dropShadow', stdDeviation: true})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: false}), "new CanvasFilter({name: 'dropShadow', stdDeviation: false})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: []}), "new CanvasFilter({name: 'dropShadow', stdDeviation: []})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [20]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [\""+(20)+"\"]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: '30'}), "new CanvasFilter({name: 'dropShadow', stdDeviation: '30'})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [10, -1]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [0.5, null]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [true, false]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [20]]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: [[], [\""+(20)+"\"]]})"); - _assert(new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]}), "new CanvasFilter({name: 'dropShadow', stdDeviation: ['30', ['40']]})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 10}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -1}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 0.5}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: null}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: true}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: false}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: []}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [20]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: '30'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [10, -1]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [0.5, null]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [true, false]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [[], [20]]}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: ['30', ['40']]}); // floodColor - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'red'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'red'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'canvas'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}), "new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#aabbccdd'})"); - _assert(new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'}), "new CanvasFilter({name: 'dropShadow', floodColor: '#abcd'})"); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'red'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'canvas'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#aabbccdd'}); + ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: '#abcd'}); + // Should throw a TypeError. // dx - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dx: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dx: [1, 2]}); }); // dy - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', dy: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', dy: [1, 2]}); }); // floodOpacity - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodOpacity: [1, 2]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodOpacity: [1, 2]}); }); // stdDeviation - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: NaN}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: -Infinity}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: {}}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, NaN]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, undefined]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, 'test']}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, {}]}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: -Infinity}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: {}}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 2, 3]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, NaN]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, -Infinity]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, undefined]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, 'test']}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, {}]}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', stdDeviation: [1, [2, 3]]}); }); // floodColor - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'test'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: 10}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: undefined}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: null}); }); - assert_throws_js(TypeError, function() { new CanvasFilter({name: 'dropShadow', floodColor: NaN}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'test'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: 10}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: undefined}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: null}); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter( + {name: 'dropShadow', floodColor: NaN}); }); t.done(); }); done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html index 81eb1eae453..7569304b95a 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.html @@ -22,86 +22,58 @@ // Parameter defaults. ctx.filter = new CanvasFilter({name: 'dropShadow'}); ctx.fillRect(10, 10, 80, 80); - // All parameters specified. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple', floodOpacity: 0.7}); ctx.fillRect(110, 10, 80, 80); - // Named color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'purple'}); ctx.fillRect(10, 110, 80, 80); - // System color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'LinkText'}); ctx.fillRect(110, 110, 80, 80); - // Numerical color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 1)'}); ctx.fillRect(210, 110, 80, 80); - // Transparent floodColor. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)'}); ctx.fillRect(310, 110, 80, 80); - // Transparent floodColor and floodOpacity. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}); ctx.fillRect(410, 110, 80, 80); - // No blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, floodColor: 'purple'}); ctx.fillRect(10, 210, 80, 80); - // Single float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple'}); ctx.fillRect(110, 210, 80, 80); - // Single negative float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, floodColor: 'purple'}); ctx.fillRect(210, 210, 80, 80); - // Two floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], floodColor: 'purple'}); ctx.fillRect(310, 210, 80, 80); - // Two negative floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], floodColor: 'purple'}); ctx.fillRect(410, 210, 80, 80); - // Degenerate parameter values. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, floodColor: 'purple', floodOpacity: [2]}); ctx.fillRect(10, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], floodColor: 'purple', floodOpacity: '0.8'}); ctx.fillRect(110, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, floodColor: 'purple', floodOpacity: ['0.4']}); ctx.fillRect(210, 310, 80, 80); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.w.html index fe9087244a0..2a26af4ec3e 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.w.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.dropShadow.tentative.w.html @@ -24,86 +24,58 @@ // Parameter defaults. ctx.filter = new CanvasFilter({name: 'dropShadow'}); ctx.fillRect(10, 10, 80, 80); - // All parameters specified. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple', floodOpacity: 0.7}); ctx.fillRect(110, 10, 80, 80); - // Named color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'purple'}); ctx.fillRect(10, 110, 80, 80); - // System color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'LinkText'}); ctx.fillRect(110, 110, 80, 80); - // Numerical color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 1)'}); ctx.fillRect(210, 110, 80, 80); - // Transparent floodColor. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)'}); ctx.fillRect(310, 110, 80, 80); - // Transparent floodColor and floodOpacity. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}); ctx.fillRect(410, 110, 80, 80); - // No blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, floodColor: 'purple'}); ctx.fillRect(10, 210, 80, 80); - // Single float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, floodColor: 'purple'}); ctx.fillRect(110, 210, 80, 80); - // Single negative float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, floodColor: 'purple'}); ctx.fillRect(210, 210, 80, 80); - // Two floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], floodColor: 'purple'}); ctx.fillRect(310, 210, 80, 80); - // Two negative floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], floodColor: 'purple'}); ctx.fillRect(410, 210, 80, 80); - // Degenerate parameter values. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, floodColor: 'purple', floodOpacity: [2]}); ctx.fillRect(10, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], floodColor: 'purple', floodOpacity: '0.8'}); ctx.fillRect(110, 310, 80, 80); - - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, + ctx.filter = new CanvasFilter({name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, floodColor: 'purple', floodOpacity: ['0.4']}); ctx.fillRect(210, 310, 80, 80); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html index 040c62a96bb..8ad2a5ccfb0 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html @@ -117,12 +117,12 @@ t.step(function() { for (testCase of errorTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - assert_throws_js(TypeError, function() { new CanvasFilter(filterOptions); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter(filterOptions); }); } for (testCase of workingTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - _assert(new CanvasFilter(filterOptions) != null, "new CanvasFilter(filterOptions) != null"); + ctx.filter = new CanvasFilter(filterOptions); } t.done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.js index 1a950a9207b..16199cb0ecf 100644 --- a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.js +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.js @@ -113,12 +113,12 @@ t.step(function() { for (testCase of errorTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - assert_throws_js(TypeError, function() { new CanvasFilter(filterOptions); }); + assert_throws_js(TypeError, function() { ctx.filter = new CanvasFilter(filterOptions); }); } for (testCase of workingTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - _assert(new CanvasFilter(filterOptions) != null, "new CanvasFilter(filterOptions) != null"); + ctx.filter = new CanvasFilter(filterOptions); } t.done(); }); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.html new file mode 100644 index 00000000000..36dd856456c --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.html @@ -0,0 +1,38 @@ + + +OffscreenCanvas test: 2d.filter.layers.blur.exceptions + + + + +

                                2d.filter.layers.blur.exceptions

                                +

                                Test exceptions on gaussianBlur filter

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.worker.js new file mode 100644 index 00000000000..a053b8113c4 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.blur.exceptions.worker.js @@ -0,0 +1,33 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.layers.blur.exceptions +// Description:Test exceptions on gaussianBlur filter +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test exceptions on gaussianBlur filter"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur'}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur', stdDeviation: undefined}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur', stdDeviation: 'foo'}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur', stdDeviation: [1,2,3]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur', stdDeviation: NaN}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'gaussianBlur', stdDeviation: {}}}); }); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.html new file mode 100644 index 00000000000..9e12acbbe0b --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.html @@ -0,0 +1,105 @@ + + +OffscreenCanvas test: 2d.filter.layers.colorMatrix + + + + +

                                2d.filter.layers.colorMatrix

                                +

                                Test the functionality of ColorMatrix filters

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.worker.js new file mode 100644 index 00000000000..12cdff38688 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.colorMatrix.worker.js @@ -0,0 +1,100 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.layers.colorMatrix +// Description:Test the functionality of ColorMatrix filters +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test the functionality of ColorMatrix filters"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', values: undefined}}); }); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', values: 'foo'}}); }); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', values: null}}); }); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', values: [1, 2, 3]}}); }); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', + values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 'a']}}); }); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'colorMatrix', + values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, Infinity]}}); }); + + ctx.fillStyle = '#f00'; + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'hueRotate', values: 0}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 255,0,0,255, 2); + + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'hueRotate', values: 90}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 0,91,0,255, 2); + + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'hueRotate', values: 180}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 0,109,109,255, 2); + + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'hueRotate', values: 270}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 109,18,255,255, 2); + + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'saturate', values: 0.5}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 155,27,27,255, 2); + + ctx.clearRect(0, 0, 100, 50); + ctx.beginLayer({filter: + {name: 'colorMatrix', type: 'luminanceToAlpha'}}); + ctx.fillRect(0, 0, 100, 50); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 0,0,0,54, 2); + + ctx.beginLayer({filter: + {name: 'colorMatrix', values: [ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0 + ]}}); + ctx.fillRect(0, 0, 50, 25); + ctx.fillStyle = '#0f0'; + ctx.fillRect(50, 0, 50, 25); + ctx.fillStyle = '#00f'; + ctx.fillRect(0, 25, 50, 25); + ctx.fillStyle = '#fff'; + ctx.fillRect(50, 25, 50, 25); + ctx.endLayer(); + _assertPixelApprox(canvas, 10,10, 0,255,0,255, 2); + _assertPixelApprox(canvas, 60,10, 0,255,0,255, 2); + _assertPixelApprox(canvas, 10,30, 0,255,0,255, 2); + _assertPixelApprox(canvas, 60,30, 0,255,0,255, 2); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete-expected.html new file mode 100644 index 00000000000..8419953b3d2 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete-expected.html @@ -0,0 +1,50 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.discrete +

                                2d.filter.layers.componentTransfer.discrete

                                +

                                Test pixels on CanvasFilter() componentTransfer with discrete type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.html new file mode 100644 index 00000000000..459c2f28504 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.html @@ -0,0 +1,41 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.discrete +

                                2d.filter.layers.componentTransfer.discrete

                                +

                                Test pixels on CanvasFilter() componentTransfer with discrete type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.w.html new file mode 100644 index 00000000000..86e1d54fb7c --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.discrete.w.html @@ -0,0 +1,55 @@ + + + + + +Canvas test: 2d.filter.layers.componentTransfer.discrete +

                                2d.filter.layers.componentTransfer.discrete

                                +

                                Test pixels on CanvasFilter() componentTransfer with discrete type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma-expected.html new file mode 100644 index 00000000000..3e5d9808967 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.gamma +

                                2d.filter.layers.componentTransfer.gamma

                                +

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.html new file mode 100644 index 00000000000..9012115adfc --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.html @@ -0,0 +1,44 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.gamma +

                                2d.filter.layers.componentTransfer.gamma

                                +

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.w.html new file mode 100644 index 00000000000..767bcc58e5f --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.gamma.w.html @@ -0,0 +1,58 @@ + + + + + +Canvas test: 2d.filter.layers.componentTransfer.gamma +

                                2d.filter.layers.componentTransfer.gamma

                                +

                                Test pixels on CanvasFilter() componentTransfer with gamma type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity-expected.html new file mode 100644 index 00000000000..9f1439f37b6 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity-expected.html @@ -0,0 +1,27 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.identity +

                                2d.filter.layers.componentTransfer.identity

                                +

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.html new file mode 100644 index 00000000000..901dae3bed4 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.html @@ -0,0 +1,37 @@ + + + +Canvas test: 2d.filter.layers.componentTransfer.identity +

                                2d.filter.layers.componentTransfer.identity

                                +

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.w.html new file mode 100644 index 00000000000..2e45018755a --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.identity.w.html @@ -0,0 +1,51 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.identity +

                                2d.filter.layers.componentTransfer.identity

                                +

                                Test pixels on CanvasFilter() componentTransfer with identity type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear-expected.html new file mode 100644 index 00000000000..f922055ff26 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear-expected.html @@ -0,0 +1,44 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.linear +

                                2d.filter.layers.componentTransfer.linear

                                +

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.html new file mode 100644 index 00000000000..f418b72ad55 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.html @@ -0,0 +1,40 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.linear +

                                2d.filter.layers.componentTransfer.linear

                                +

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.w.html new file mode 100644 index 00000000000..fbc29c86c17 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.linear.w.html @@ -0,0 +1,54 @@ + + + + + +Canvas test: 2d.filter.layers.componentTransfer.linear +

                                2d.filter.layers.componentTransfer.linear

                                +

                                Test pixels on CanvasFilter() componentTransfer with linear type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table-expected.html new file mode 100644 index 00000000000..0f6736d87d4 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table-expected.html @@ -0,0 +1,51 @@ + + +Canvas test: 2d.filter.layers.componentTransfer.table +

                                2d.filter.layers.componentTransfer.table

                                +

                                Test pixels on CanvasFilter() componentTransfer with table type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.html new file mode 100644 index 00000000000..ef5e0f847ba --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.html @@ -0,0 +1,41 @@ + + + + +Canvas test: 2d.filter.layers.componentTransfer.table +

                                2d.filter.layers.componentTransfer.table

                                +

                                Test pixels on CanvasFilter() componentTransfer with table type

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.w.html new file mode 100644 index 00000000000..b11f0ef6f30 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.componentTransfer.table.w.html @@ -0,0 +1,55 @@ + + + + + +Canvas test: 2d.filter.layers.componentTransfer.table +

                                2d.filter.layers.componentTransfer.table

                                +

                                Test pixels on CanvasFilter() componentTransfer with table type

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.html new file mode 100644 index 00000000000..798822f1042 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.html @@ -0,0 +1,61 @@ + + +OffscreenCanvas test: 2d.filter.layers.convolveMatrix.exceptions + + + + +

                                2d.filter.layers.convolveMatrix.exceptions

                                +

                                Test exceptions on CanvasFilter() convolveMatrix

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.worker.js new file mode 100644 index 00000000000..fa3be89ba2f --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.convolveMatrix.exceptions.worker.js @@ -0,0 +1,56 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.layers.convolveMatrix.exceptions +// Description:Test exceptions on CanvasFilter() convolveMatrix +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test exceptions on CanvasFilter() convolveMatrix"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix'}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', divisor: 2}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: null}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: 1}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: []}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [1]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[], []]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}}); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}}); }); + // This should not throw an error + ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[]]}}); + ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'convolveMatrix', kernelMatrix: [[1]]}}); + ctx.endLayer(); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow-expected.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow-expected.html new file mode 100644 index 00000000000..1719d99b4a7 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow-expected.html @@ -0,0 +1,57 @@ + + +Canvas test: 2d.filter.layers.dropShadow +

                                2d.filter.layers.dropShadow

                                +

                                Test CanvasFilter() dropShadow object.

                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.html new file mode 100644 index 00000000000..10392dea5ac --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.html @@ -0,0 +1,270 @@ + + +OffscreenCanvas test: 2d.filter.layers.dropShadow.exceptions + + + + +

                                2d.filter.layers.dropShadow.exceptions

                                +

                                Test exceptions on CanvasFilter() dropShadow object

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.worker.js new file mode 100644 index 00000000000..86b8c56af69 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.exceptions.worker.js @@ -0,0 +1,265 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.layers.dropShadow.exceptions +// Description:Test exceptions on CanvasFilter() dropShadow object +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test exceptions on CanvasFilter() dropShadow object"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + // Should not throw an error. + // dx + ctx.beginLayer({filter: + {name: 'dropShadow', dx: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: '30'}}); ctx.endLayer(); + // dy + ctx.beginLayer({filter: + {name: 'dropShadow', dy: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: '30'}}); ctx.endLayer(); + // floodOpacity + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: '30'}}); ctx.endLayer(); + // dx + ctx.beginLayer({filter: + {name: 'dropShadow', dx: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dx: '30'}}); ctx.endLayer(); + // dy + ctx.beginLayer({filter: + {name: 'dropShadow', dy: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', dy: '30'}}); ctx.endLayer(); + // floodOpacity + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: '30'}}); ctx.endLayer(); + // stdDeviation + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: 10}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: -1}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: 0.5}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: null}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: true}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: false}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: []}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [20]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: '30'}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [10, -1]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [0.5, null]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [true, false]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [[], [20]]}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: ['30', ['40']]}}); ctx.endLayer(); + // floodColor + ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 'red'}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 'canvas'}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 'rgba(4, -3, 0.5, 1)'}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: '#aabbccdd'}}); ctx.endLayer(); + ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: '#abcd'}}); ctx.endLayer(); + + // Should throw a TypeError. + // dx + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: NaN}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: -Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: undefined}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: 'test'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: {}}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dx: [1, 2]}}); ctx.endLayer(); }); + // dy + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: NaN}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: -Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: undefined}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: 'test'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: {}}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', dy: [1, 2]}}); ctx.endLayer(); }); + // floodOpacity + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: NaN}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: -Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: undefined}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: 'test'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: {}}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodOpacity: [1, 2]}}); ctx.endLayer(); }); + // stdDeviation + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: NaN}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: -Infinity}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: undefined}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: 'test'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: {}}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, 2, 3]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, NaN]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, Infinity]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, -Infinity]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, undefined]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, 'test']}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, {}]}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', stdDeviation: [1, [2, 3]]}}); ctx.endLayer(); }); + // floodColor + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 'test'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 'rgba(NaN, 3, 2, 1)'}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: 10}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: undefined}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: null}}); ctx.endLayer(); }); + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: + {name: 'dropShadow', floodColor: NaN}}); ctx.endLayer(); }); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.html new file mode 100644 index 00000000000..1ecf309fc4e --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.html @@ -0,0 +1,97 @@ + + + +Canvas test: 2d.filter.layers.dropShadow +

                                2d.filter.layers.dropShadow

                                +

                                Test CanvasFilter() dropShadow object.

                                + +

                                FAIL (fallback content)

                                +
                                + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.w.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.w.html new file mode 100644 index 00000000000..e73b573779e --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.dropShadow.w.html @@ -0,0 +1,111 @@ + + + + +Canvas test: 2d.filter.layers.dropShadow +

                                2d.filter.layers.dropShadow

                                +

                                Test CanvasFilter() dropShadow object.

                                + +

                                FAIL (fallback content)

                                +
                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.html b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.html new file mode 100644 index 00000000000..27f7748c847 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.html @@ -0,0 +1,131 @@ + + +OffscreenCanvas test: 2d.filter.layers.turbulence.inputTypes + + + + +

                                2d.filter.layers.turbulence.inputTypes

                                +

                                Test exceptions on CanvasFilter() turbulence object

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.worker.js b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.worker.js new file mode 100644 index 00000000000..3728566c997 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/filters/2d.filter.layers.turbulence.inputTypes.worker.js @@ -0,0 +1,126 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.layers.turbulence.inputTypes +// Description:Test exceptions on CanvasFilter() turbulence object +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test exceptions on CanvasFilter() turbulence object"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + const errorTestCases = [ + {baseFrequency: {}}, + {baseFrequency: -1}, + {baseFrequency: [0, -1]}, + {baseFrequency: NaN}, + {baseFrequency: Infinity}, + {baseFrequency: undefined}, + {baseFrequency: -Infinity}, + {baseFrequency: 'test'}, + + {numOctaves: {}}, + {numOctaves: -1}, + {numOctaves: NaN}, + {numOctaves: Infinity}, + {numOctaves: undefined}, + {numOctaves: -Infinity}, + {numOctaves: [1, 1]}, + {numOctaves: 'test'}, + + {seed: {}}, + {seed: NaN}, + {seed: Infinity}, + {seed: undefined}, + {seed: -Infinity}, + {seed: [1, 1]}, + {seed: 'test'}, + + {stitchTiles: {}}, + {stitchTiles: NaN}, + {stitchTiles: Infinity}, + {stitchTiles: undefined}, + {stitchTiles: -Infinity}, + {stitchTiles: [1, 1]}, + {stitchTiles: 'test'}, + {stitchTiles: null}, + {stitchTiles: []}, + {stitchTiles: [10]}, + {stitchTiles: 30}, + {stitchTiles: false}, + {stitchTiles: true}, + {stitchTiles: '10'}, + {stitchTiles: -1}, + + {type: {}}, + {type: NaN}, + {type: Infinity}, + {type: undefined}, + {type: -Infinity}, + {type: [1, 1]}, + {type: 'test'}, + {type: null}, + {type: []}, + {type: [10]}, + {type: 30}, + {type: false}, + {type: true}, + {type: '10'}, + {type: -1}, + ] + + // null and [] = 0 when parsed as number + const workingTestCases = [ + {baseFrequency: null}, + {baseFrequency: []}, + {baseFrequency: [10]}, + {baseFrequency: [10, 3]}, + {baseFrequency: 30}, + {baseFrequency: false}, + {baseFrequency: true}, + {baseFrequency: '10'}, + + {numOctaves: null}, + {numOctaves: []}, + {numOctaves: [10]}, + {numOctaves: 30}, + {numOctaves: false}, + {numOctaves: true}, + {numOctaves: '10'}, + + {seed: null}, + {seed: []}, + {seed: [10]}, + {seed: 30}, + {seed: false}, + {seed: true}, + {seed: '10'}, + {seed: -1}, + + {stitchTiles: 'stitch'}, + {stitchTiles: 'noStitch'}, + + {type: 'fractalNoise'}, + {type: 'turbulence'}, + ] + + for (testCase of errorTestCases) { + const filterOptions = {...{name: 'turbulence'}, ...testCase}; + assert_throws_js(TypeError, function() { ctx.beginLayer({filter: filterOptions}); }); + } + + for (testCase of workingTestCases) { + const filterOptions = {...{name: 'turbulence'}, ...testCase}; + ctx.beginLayer({filter: filterOptions}); + ctx.endLayer(); + } + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html b/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html index 1e5c6ad8b75..0e48cb49f79 100644 --- a/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html +++ b/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html @@ -1,7 +1,7 @@ - + Canvas test: 2d.layer.global-states.filter.alpha.blending

                                2d.layer.global-states.filter.alpha.blending

                                Checks that layers with filters correctly use global render states.

                                diff --git a/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html b/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html index 142e900fd1b..3887ed4485b 100644 --- a/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html +++ b/tests/wpt/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html @@ -2,7 +2,7 @@ - + Canvas test: 2d.layer.global-states.filter.alpha.blending

                                2d.layer.global-states.filter.alpha.blending

                                Checks that layers with filters correctly use global render states.

                                diff --git a/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html new file mode 100644 index 00000000000..cd478e666fd --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.html @@ -0,0 +1,27 @@ + + +OffscreenCanvas test: 2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https + + + + +

                                2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https

                                +

                                getTextureFormat() returns RGBA16F for a float16 context

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.worker.js b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.worker.js new file mode 100644 index 00000000000..f24b8aa8504 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https.worker.js @@ -0,0 +1,22 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https +// Description:getTextureFormat() returns RGBA16F for a float16 context +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("getTextureFormat() returns RGBA16F for a float16 context"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d', {colorSpace: "display-p3", pixelFormat: "float16"}); + + _assertSame(ctx.getTextureFormat(), "rgba16float", "ctx.getTextureFormat()", "\"rgba16float\""); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html new file mode 100644 index 00000000000..d77a2984087 --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.html @@ -0,0 +1,27 @@ + + +OffscreenCanvas test: 2d.webgpuaccess.getTextureFormat.rgba8.tentative.https + + + + +

                                2d.webgpuaccess.getTextureFormat.rgba8.tentative.https

                                +

                                getTextureFormat() returns RGBA8 or BGRA8 for a typical context

                                + + + diff --git a/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.worker.js b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.worker.js new file mode 100644 index 00000000000..4d4137e2d3c --- /dev/null +++ b/tests/wpt/tests/html/canvas/offscreen/webgpu-access/2d.webgpuaccess.getTextureFormat.rgba8.tentative.https.worker.js @@ -0,0 +1,22 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.webgpuaccess.getTextureFormat.rgba8.tentative.https +// Description:getTextureFormat() returns RGBA8 or BGRA8 for a typical context +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("getTextureFormat() returns RGBA8 or BGRA8 for a typical context"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + assert_regexp_match(ctx.getTextureFormat(), /^rgba8unorm|bgra8unorm$/); + t.done(); +}); +done(); diff --git a/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py b/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py index 4fe7f2bd42e..d7042810be8 100644 --- a/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py +++ b/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py @@ -184,6 +184,10 @@ def _remove_extra_newlines(text: str) -> str: return text def _expand_test_code(code: str) -> str: + code = re.sub(r' @moz-todo', '', code) + + code = re.sub(r'@moz-UniversalBrowserRead;', '', code) + code = _remove_extra_newlines(code) # Unroll expressions with a cross-product-style parameter expansion. @@ -202,11 +206,13 @@ def _expand_test_code(code: str) -> str: code = re.sub(r'@assert pixel (\d+,\d+) ==~ (\d+,\d+,\d+,\d+) \+/- (\d+);', r'_assertPixelApprox(canvas, \1, \2, \3);', code) - code = re.sub(r'@assert throws (\S+_ERR) (.*);', - r'assert_throws_dom("\1", function() { \2; });', code) + code = re.sub(r'@assert throws (\S+_ERR) (.*?);$', + r'assert_throws_dom("\1", function() { \2; });', code, + flags=re.MULTILINE | re.DOTALL) - code = re.sub(r'@assert throws (\S+Error) (.*);', - r'assert_throws_js(\1, function() { \2; });', code) + code = re.sub(r'@assert throws (\S+Error) (.*?);$', + r'assert_throws_js(\1, function() { \2; });', code, + flags=re.MULTILINE | re.DOTALL) code = re.sub( r'@assert (.*) === (.*);', lambda m: '_assertSame(%s, %s, "%s", "%s");' @@ -226,10 +232,6 @@ def _expand_test_code(code: str) -> str: r'@assert (.*);', lambda m: '_assert(%s, "%s");' % (m.group( 1), _escapeJS(m.group(1))), code) - code = re.sub(r' @moz-todo', '', code) - - code = re.sub(r'@moz-UniversalBrowserRead;', '', code) - assert ('@' not in code) return code diff --git a/tests/wpt/tests/html/canvas/tools/name2dir-canvas.yaml b/tests/wpt/tests/html/canvas/tools/name2dir-canvas.yaml index 1e0caff5b98..79b5fb61f28 100644 --- a/tests/wpt/tests/html/canvas/tools/name2dir-canvas.yaml +++ b/tests/wpt/tests/html/canvas/tools/name2dir-canvas.yaml @@ -24,3 +24,4 @@ 2d.video: "video" 2d.canvas.host: "canvas-host" 2d.canvas.context: "canvas-context" +2d.webgpuaccess: "webgpu-access" diff --git a/tests/wpt/tests/html/canvas/tools/name2dir-offscreen.yaml b/tests/wpt/tests/html/canvas/tools/name2dir-offscreen.yaml index c52acb793ba..3f59fd8eead 100644 --- a/tests/wpt/tests/html/canvas/tools/name2dir-offscreen.yaml +++ b/tests/wpt/tests/html/canvas/tools/name2dir-offscreen.yaml @@ -19,4 +19,5 @@ 2d.missingargs: "conformance-requirements" 2d.voidreturn: "conformance-requirements" 2d.canvas.host: "canvas-host" -2d.canvas.context: "canvas-context" \ No newline at end of file +2d.canvas.context: "canvas-context" +2d.webgpuaccess: "webgpu-access" diff --git a/tests/wpt/tests/html/canvas/tools/name2dir.yaml b/tests/wpt/tests/html/canvas/tools/name2dir.yaml index ae69c153780..b0e541289f5 100644 --- a/tests/wpt/tests/html/canvas/tools/name2dir.yaml +++ b/tests/wpt/tests/html/canvas/tools/name2dir.yaml @@ -23,3 +23,4 @@ 2d.video: "video" 2d.canvas.host: "canvas-host" 2d.canvas.context: "canvas-context" +2d.webgpuaccess: "webgpu-access" diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/drawing-images-to-the-canvas.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/drawing-images-to-the-canvas.yaml index 93c556288d7..09e9e001867 100644 --- a/tests/wpt/tests/html/canvas/tools/yaml-new/drawing-images-to-the-canvas.yaml +++ b/tests/wpt/tests/html/canvas/tools/yaml-new/drawing-images-to-the-canvas.yaml @@ -638,3 +638,11 @@ @nonfinite ctx.drawImage(, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); @assert pixel 50,25 == 0,255,0,255; expected: green + +- name: 2d.drawImage.detachedcanvas + desc: drawImage with detached OffscreenCanvas as the source should throw exception + canvasType: ['HTMLCanvas'] + code: | + var canvas2 = new OffscreenCanvas(80, 80); + (new MessageChannel()).port1.postMessage(canvas2, [canvas2]); + @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0); diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/filters.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/filters.yaml index e18ab61b41e..f327b9fe949 100644 --- a/tests/wpt/tests/html/canvas/tools/yaml-new/filters.yaml +++ b/tests/wpt/tests/html/canvas/tools/yaml-new/filters.yaml @@ -89,51 +89,102 @@ ctx.filter = 'this string is not a filter and should do nothing'; @assert ctx.filter.toString() == '[object CanvasFilter]'; -- name: 2d.filter.canvasFilterObject.blur.exceptions.tentative - desc: Test exceptions on CanvasFilter() blur.object +- name: 2d.filter.{{ variant_names[0] }}.blur.exceptions{{ tentative }} + desc: Test exceptions on gaussianBlur filter code: | - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur'}); - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur', stdDeviation: undefined}); - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur', stdDeviation: 'foo'}); - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur', stdDeviation: [1,2,3]}); - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur', stdDeviation: NaN}); - @assert throws TypeError ctx.filter = new CanvasFilter({name: 'gaussianBlur', stdDeviation: {}}); + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur'}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur', stdDeviation: undefined}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur', stdDeviation: 'foo'}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur', stdDeviation: [1,2,3]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur', stdDeviation: NaN}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'gaussianBlur', stdDeviation: {}}") }}; + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: + param}) + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter( + param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.colorMatrix.tentative - desc: Test the functionality of ColorMatrix filters in CanvasFilter objects +- name: 2d.filter.{{ variant_names[0] }}.colorMatrix{{ tentative }} + desc: Test the functionality of ColorMatrix filters code: | - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: undefined}); - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: 'foo'}); - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: null}); - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: [1, 2, 3]}); - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 'a']}); - @assert throws TypeError new CanvasFilter({name: 'colorMatrix', values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, Infinity]}); + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', values: undefined}") }}; + + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', values: 'foo'}") }}; + + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', values: null}") }}; + + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', values: [1, 2, 3]}") }}; + + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', + values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 'a']}") }}; + + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'colorMatrix', + values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, Infinity]}") }}; + ctx.fillStyle = '#f00'; - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'hueRotate', values: 0}); + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'hueRotate', values: 0}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 255,0,0,255; - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'hueRotate', values: 90}); + + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'hueRotate', values: 90}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 0,91,0,255; - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'hueRotate', values: 180}); + + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'hueRotate', values: 180}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 0,109,109,255; - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'hueRotate', values: 270}); + + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'hueRotate', values: 270}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 109,18,255,255; - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'saturate', values: 0.5}); + + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'saturate', values: 0.5}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 155,27,27,255; + ctx.clearRect(0, 0, 100, 50); - ctx.filter = new CanvasFilter({name: 'colorMatrix', type: 'luminanceToAlpha'}); + {{ filter_declaration | replace("param", + "{name: 'colorMatrix', type: 'luminanceToAlpha'}") }}; ctx.fillRect(0, 0, 100, 50); + {{ close_layer -}} @assert pixel 10,10 ==~ 0,0,0,54; - ctx.filter = new CanvasFilter({name: 'colorMatrix', values: [ - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0 - ]}); + + {{ filter_declaration | replace("param", "{name: 'colorMatrix', values: [ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0 + ]}") }}; ctx.fillRect(0, 0, 50, 25); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 25); @@ -141,51 +192,120 @@ ctx.fillRect(0, 25, 50, 25); ctx.fillStyle = '#fff'; ctx.fillRect(50, 25, 50, 25); + {{ close_layer -}} @assert pixel 10,10 ==~ 0,255,0,255; @assert pixel 60,10 ==~ 0,255,0,255; @assert pixel 10,30 ==~ 0,255,0,255; @assert pixel 60,30 ==~ 0,255,0,255; + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: + param}) + close_layer: | + ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter( + param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative +- name: 2d.filter.{{ variant_names[0] }}.convolveMatrix.exceptions{{ tentative }} desc: Test exceptions on CanvasFilter() convolveMatrix code: | - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix'}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', divisor: 2}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: null}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: 1}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: []}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], []]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); - @assert throws TypeError new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix'}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', divisor: 2}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: null}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: 1}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: []}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [1]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[], []]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1, 2], []]}") }}; + @assert throws TypeError {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}") }}; // This should not throw an error - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[]]}); - ctx.filter = new CanvasFilter({name: 'convolveMatrix', kernelMatrix: [[1]]}); + {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[]]}") }}; + {{ close_layer -}} + {{ filter_declaration | replace("param", + "{name: 'convolveMatrix', kernelMatrix: [[1]]}") }}; + {{ close_layer -}} + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: + param}) + close_layer: | + ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter( + param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative +- name: >- + 2d.filter.{{ variant_names[0] }}.componentTransfer.linear{{ tentative }} desc: Test pixels on CanvasFilter() componentTransfer with linear type + size: [100, 100] + fuzzy: maxDifference=0-2; totalPixels=0-500 code: | + const slopes = [0.5, 1.2, -0.2]; + const intercepts = [0.25, 0, 0.5]; + {{ filter_declaration | replace("param", "{name: 'componentTransfer', + funcR: {type: 'linear', slope: slopes[0], intercept: intercepts[0]}, + funcG: {type: 'linear', slope: slopes[1], intercept: intercepts[1]}, + funcB: {type: 'linear', slope: slopes[2], intercept: intercepts[2]}, + }") }}; + + const inputColors = [ + [255, 255, 255], + [0, 0, 0], + [127, 0, 34], + [252, 186, 3], + [50, 68, 87], + ]; + + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); + } + {{ close_layer }} + reference: | // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement function getColor(inputColor, slopes, intercepts) { return [ - Math.max(0, Math.min(1, inputColor[0]/255 * slopes[0] + intercepts[0])) * 255, - Math.max(0, Math.min(1, inputColor[1]/255 * slopes[1] + intercepts[1])) * 255, - Math.max(0, Math.min(1, inputColor[2]/255 * slopes[2] + intercepts[2])) * 255, + Math.max(0, Math.min(1, + inputColor[0]/255 * slopes[0] + intercepts[0])) * 255, + Math.max(0, Math.min(1, + inputColor[1]/255 * slopes[1] + intercepts[1])) * 255, + Math.max(0, Math.min(1, + inputColor[2]/255 * slopes[2] + intercepts[2])) * 255, ]; } const slopes = [0.5, 1.2, -0.2]; const intercepts = [0.25, 0, 0.5]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'linear', slope: slopes[0], intercept: intercepts[0]}, - funcG: {type: 'linear', slope: slopes[1], intercept: intercepts[1]}, - funcB: {type: 'linear', slope: slopes[2], intercept: intercepts[2]}, - }); const inputColors = [ [255, 255, 255], @@ -195,21 +315,35 @@ [50, 68, 87], ]; - for (const color of inputColors) { + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; let outputColor = getColor(color, slopes, intercepts); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); + ctx.fillStyle = `rgb(${outputColor[0]}, ${outputColor[1]}, + ${outputColor[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); } + {{ close_layer }} + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative +- name: >- + 2d.filter.{{ variant_names[0] }}.componentTransfer.identity{{ tentative }} desc: Test pixels on CanvasFilter() componentTransfer with identity type + size: [100, 100] code: | - ctx.filter = new CanvasFilter({name: 'componentTransfer', + {{ filter_declaration | replace("param", "{name: 'componentTransfer', funcR: {type: 'identity'}, funcG: {type: 'identity'}, funcB: {type: 'identity'}, - }); + }") }}; const inputColors = [ [255, 255, 255], @@ -219,32 +353,86 @@ [50, 68, 87], ]; - for (const color of inputColors) { - ctx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, 1)`, - ctx.fillRect(0, 0, 10, 10); - _assertPixel(canvas, 5, 5, color[0],color[1],color[2],255); + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); } + {{ close_layer }} + reference: | + const inputColors = [ + [255, 255, 255], + [0, 0, 0], + [127, 0, 34], + [252, 186, 3], + [50, 68, 87], + ]; -- name: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative + for (let i = 0 ; i < inputColors.length ; ++i) { + let outputColor = inputColors[i]; + ctx.fillStyle = `rgb(${outputColor[0]}, ${outputColor[1]}, + ${outputColor[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); + } + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative + +- name: >- + 2d.filter.{{ variant_names[0] }}.componentTransfer.gamma{{ tentative }} desc: Test pixels on CanvasFilter() componentTransfer with gamma type + size: [100, 100] + fuzzy: maxDifference=0-2; totalPixels=0-500 code: | + const amplitudes = [2, 1.1, 0.5]; + const exponents = [5, 3, 1]; + const offsets = [0.25, 0, 0.5]; + {{ filter_declaration | replace("param", "{name: 'componentTransfer', + funcR: {type: 'gamma', amplitude: amplitudes[0], + exponent: exponents[0], offset: offsets[0]}, + funcG: {type: 'gamma', amplitude: amplitudes[1], + exponent: exponents[1], offset: offsets[1]}, + funcB: {type: 'gamma', amplitude: amplitudes[2], + exponent: exponents[2], offset: offsets[2]}, + }") }}; + + const inputColors = [ + [255, 255, 255], + [0, 0, 0], + [127, 0, 34], + [252, 186, 3], + [50, 68, 87], + ]; + + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); + } + {{ close_layer }} + reference: | // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement function getColor(inputColor, amplitude, exponent, offset) { return [ - Math.max(0, Math.min(1, Math.pow(inputColor[0]/255, exponent[0]) * amplitude[0] + offset[0])) * 255, - Math.max(0, Math.min(1, Math.pow(inputColor[1]/255, exponent[1]) * amplitude[1] + offset[1])) * 255, - Math.max(0, Math.min(1, Math.pow(inputColor[2]/255, exponent[2]) * amplitude[2] + offset[2])) * 255, + Math.max(0, Math.min(1, Math.pow(inputColor[0]/255, + exponent[0]) * amplitude[0] + offset[0])) * 255, + Math.max(0, Math.min(1, Math.pow(inputColor[1]/255, + exponent[1]) * amplitude[1] + offset[1])) * 255, + Math.max(0, Math.min(1, Math.pow(inputColor[2]/255, + exponent[2]) * amplitude[2] + offset[2])) * 255, ]; } const amplitudes = [2, 1.1, 0.5]; const exponents = [5, 3, 1]; const offsets = [0.25, 0, 0.5]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'gamma', amplitude: amplitudes[0], exponent: exponents[0], offset: offsets[0]}, - funcG: {type: 'gamma', amplitude: amplitudes[1], exponent: exponents[1], offset: offsets[1]}, - funcB: {type: 'gamma', amplitude: amplitudes[2], exponent: exponents[2], offset: offsets[2]}, - }); const inputColors = [ [255, 255, 255], @@ -254,16 +442,54 @@ [50, 68, 87], ]; - for (const color of inputColors) { + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; let outputColor = getColor(color, amplitudes, exponents, offsets); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); + ctx.fillStyle = `rgb(${outputColor[0]}, ${outputColor[1]}, + ${outputColor[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); } + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.componentTransfer.table.tentative +- name: >- + 2d.filter.{{ variant_names[0] }}.componentTransfer.table{{ tentative }} desc: Test pixels on CanvasFilter() componentTransfer with table type + size: [100, 100] + fuzzy: maxDifference=0-2; totalPixels=0-500 code: | + tableValuesR = [0, 0, 1, 1]; + tableValuesG = [2, 0, 0.5, 3]; + tableValuesB = [1, -1, 5, 0]; + {{ filter_declaration | replace("param", "{name: 'componentTransfer', + funcR: {type: 'table', tableValues: tableValuesR}, + funcG: {type: 'table', tableValues: tableValuesG}, + funcB: {type: 'table', tableValues: tableValuesB}, + }") }}; + + const inputColors = [ + [255, 255, 255], + [0, 0, 0], + [127, 0, 34], + [252, 186, 3], + [50, 68, 87], + ]; + + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); + } + {{ close_layer }} + reference: | // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement function getTransformedValue(C, V) { // Get the right interval @@ -285,11 +511,6 @@ tableValuesR = [0, 0, 1, 1]; tableValuesG = [2, 0, 0.5, 3]; tableValuesB = [1, -1, 5, 0]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'table', tableValues: tableValuesR}, - funcG: {type: 'table', tableValues: tableValuesG}, - funcB: {type: 'table', tableValues: tableValuesB}, - }); const inputColors = [ [255, 255, 255], @@ -299,16 +520,55 @@ [50, 68, 87], ]; - for (const color of inputColors) { - let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + let outputColor = getColor( + color, [tableValuesR, tableValuesG, tableValuesB]); + ctx.fillStyle = `rgb(${outputColor[0]}, ${outputColor[1]}, + ${outputColor[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); } + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative +- name: >- + 2d.filter.{{ variant_names[0] }}.componentTransfer.discrete{{ tentative }} desc: Test pixels on CanvasFilter() componentTransfer with discrete type + size: [100, 100] + fuzzy: maxDifference=0-2; totalPixels=0-500 code: | + tableValuesR = [0, 0, 1, 1]; + tableValuesG = [2, 0, 0.5, 3]; + tableValuesB = [1, -1, 5, 0]; + {{ filter_declaration | replace("param", "{name: 'componentTransfer', + funcR: {type: 'discrete', tableValues: tableValuesR}, + funcG: {type: 'discrete', tableValues: tableValuesG}, + funcB: {type: 'discrete', tableValues: tableValuesB}, + }") }}; + + const inputColors = [ + [255, 255, 255], + [0, 0, 0], + [127, 0, 34], + [252, 186, 3], + [50, 68, 87], + ]; + + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); + } + {{ close_layer }} + reference: | // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement function getTransformedValue(C, V) { // Get the right interval @@ -330,11 +590,6 @@ tableValuesR = [0, 0, 1, 1]; tableValuesG = [2, 0, 0.5, 3]; tableValuesB = [1, -1, 5, 0]; - ctx.filter = new CanvasFilter({name: 'componentTransfer', - funcR: {type: 'discrete', tableValues: tableValuesR}, - funcG: {type: 'discrete', tableValues: tableValuesG}, - funcB: {type: 'discrete', tableValues: tableValuesB}, - }); const inputColors = [ [255, 255, 255], @@ -343,13 +598,24 @@ [252, 186, 3], [50, 68, 87], ]; - - for (const color of inputColors) { - let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); - ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; - ctx.fillRect(0, 0, 10, 10); - _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, 2); + for (let i = 0 ; i < inputColors.length ; ++i) { + const color = inputColors[i]; + let outputColor = getColor( + color, [tableValuesR, tableValuesG, tableValuesB]); + ctx.fillStyle = `rgb(${outputColor[0]}, ${outputColor[1]}, + ${outputColor[2]})`; + ctx.fillRect(i * 10, i * 10, 10, 10); } + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative - name: >- 2d.filter.{{ variant_names[0] }}.gaussianBlur.{{ variant_names[1] }}{{ @@ -400,7 +666,7 @@ blur_x: 0 blur_y: 4 -- name: 2d.filter.canvasFilterObject.dropShadow.tentative +- name: 2d.filter.{{ variant_names[0] }}.dropShadow{{ tentative }} desc: Test CanvasFilter() dropShadow object. size: [520, 420] code: | @@ -413,90 +679,91 @@ ctx.fillStyle = 'crimson'; // Parameter defaults. - ctx.filter = new CanvasFilter({name: 'dropShadow'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow'}") }} ctx.fillRect(10, 10, 80, 80); + {{ close_layer -}} // All parameters specified. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, - floodColor: 'purple', floodOpacity: 0.7}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + floodColor: 'purple', floodOpacity: 0.7}") }} ctx.fillRect(110, 10, 80, 80); + {{ close_layer -}} // Named color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + floodColor: 'purple'}") }} ctx.fillRect(10, 110, 80, 80); + {{ close_layer -}} // System color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, - floodColor: 'LinkText'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + floodColor: 'LinkText'}") }} ctx.fillRect(110, 110, 80, 80); + {{ close_layer -}} // Numerical color. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, - floodColor: 'rgba(20, 50, 130, 1)'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + floodColor: 'rgba(20, 50, 130, 1)'}") }} ctx.fillRect(210, 110, 80, 80); + {{ close_layer -}} // Transparent floodColor. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, - floodColor: 'rgba(20, 50, 130, 0.7)'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + floodColor: 'rgba(20, 50, 130, 0.7)'}") }} ctx.fillRect(310, 110, 80, 80); + {{ close_layer -}} // Transparent floodColor and floodOpacity. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, - floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, + floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}") }} ctx.fillRect(410, 110, 80, 80); + {{ close_layer -}} // No blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, + floodColor: 'purple'}") }} ctx.fillRect(10, 210, 80, 80); + {{ close_layer -}} // Single float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, + floodColor: 'purple'}") }} ctx.fillRect(110, 210, 80, 80); + {{ close_layer -}} // Single negative float blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, + floodColor: 'purple'}") }} ctx.fillRect(210, 210, 80, 80); + {{ close_layer -}} // Two floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], + floodColor: 'purple'}") }} ctx.fillRect(310, 210, 80, 80); + {{ close_layer -}} // Two negative floats (X&Y) blur. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], - floodColor: 'purple'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], + floodColor: 'purple'}") }} ctx.fillRect(410, 210, 80, 80); + {{ close_layer -}} // Degenerate parameter values. - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, - floodColor: 'purple', floodOpacity: [2]}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, + floodColor: 'purple', floodOpacity: [2]}") }} ctx.fillRect(10, 310, 80, 80); + {{ close_layer -}} - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], - floodColor: 'purple', floodOpacity: '0.8'}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], + floodColor: 'purple', floodOpacity: '0.8'}") }} ctx.fillRect(110, 310, 80, 80); + {{ close_layer -}} - ctx.filter = new CanvasFilter( - {name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, - floodColor: 'purple', floodOpacity: ['0.4']}); + {{ filter_declaration | replace("param", "{name: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, + floodColor: 'purple', floodOpacity: ['0.4']}") }} ctx.fillRect(210, 310, 80, 80); + {{ close_layer -}} html_reference: | + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}); + close_layer: | + ctx.endLayer(); + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param); + tentative: .tentative -- name: 2d.filter.canvasFilterObject.dropShadow.exceptions.tentative +- name: 2d.filter.{{ variant_names[0] }}.dropShadow.exceptions{{ tentative }} desc: Test exceptions on CanvasFilter() dropShadow object code: | - @unroll @assert new CanvasFilter({\- + // Should not throw an error. + @unroll {{ filter_declaration | replace("param", "{\- name: 'dropShadow', \- : \- - <10 | -1 | 0.5 | null | true | false | [] | [20] | '30'>}); - @unroll @assert new CanvasFilter({\- + <10 | -1 | 0.5 | null | true | false | [] | [20] | '30'>}") }}; + @unroll {{ filter_declaration | replace("param", "{\- + name: 'dropShadow', \- + : \- + <10 | -1 | 0.5 | null | true | false | [] | [20] | '30'>}") }}; + @unroll {{ filter_declaration | replace("param", "{\- name: 'dropShadow', \- : \- <10 | -1 | 0.5 | null | true | false | [] | [20] | '30' | \- [10, -1] | [0.5, null] | [true, false] | [[], [20]] | \- - ['30', ['40']]>}); - @unroll @assert new CanvasFilter({\- + ['30', ['40']]>}") }}; + @unroll {{ filter_declaration | replace("param", "{\- name: 'dropShadow', \- : \- - <'red' | 'canvas' | 'rgba(4, -3, 0.5, 1)' | '#aabbccdd' | '#abcd'>}); + <'red' | 'canvas' | 'rgba(4, -3, 0.5, 1)' | '#aabbccdd' | + '#abcd'>}") }}; - @unroll @assert throws TypeError new CanvasFilter({\- - name: 'dropShadow', \- + // Should throw a TypeError. + @unroll @assert throws TypeError {{ filter_declaration | replace("param", \- + "{name: 'dropShadow', \- : \- - }); - @unroll @assert throws TypeError new CanvasFilter({\- - name: 'dropShadow', \- + }") }}; + @unroll @assert throws TypeError {{ filter_declaration | replace("param", \- + "{name: 'dropShadow', \- : \- }); - @unroll @assert throws TypeError new CanvasFilter({\- - name: 'dropShadow', \- + [1, 'test'] | [1, {}] | [1, [2, 3]]>}") }}; + @unroll @assert throws TypeError {{ filter_declaration | replace("param", \- + "{name: 'dropShadow', \- : \- - <'test' | 'rgba(NaN, 3, 2, 1)' | 10 | undefined | null | NaN>}); + <'test' | 'rgba(NaN, 3, 2, 1)' | 10 | undefined | null | NaN>}") }}; + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: + param}); ctx.endLayer() + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter( + param) + tentative: .tentative -- name: 2d.filter.canvasFilterObject.turbulence.inputTypes.tentative +- name: 2d.filter.{{ variant_names[0] }}.turbulence.inputTypes{{ tentative }} desc: Test exceptions on CanvasFilter() turbulence object code: | const errorTestCases = [ @@ -683,10 +979,22 @@ for (testCase of errorTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - @assert throws TypeError new CanvasFilter(filterOptions); + @assert throws TypeError {{ filter_declaration | + replace("param", "filterOptions") }}; } for (testCase of workingTestCases) { const filterOptions = {...{name: 'turbulence'}, ...testCase}; - @assert new CanvasFilter(filterOptions) != null; + {{ filter_declaration | replace("param", "filterOptions") }}; + {{- close_layer }} } + append_variants_to_name: false + variants: + layers: + filter_declaration: |- + ctx.beginLayer({filter: param}) + close_layer: "\n ctx.endLayer();" + canvasFilterObject: + filter_declaration: |- + ctx.filter = new CanvasFilter(param) + tentative: .tentative diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/layers.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/layers.yaml index 938cc74d214..437a70c3f7a 100644 --- a/tests/wpt/tests/html/canvas/tools/yaml-new/layers.yaml +++ b/tests/wpt/tests/html/canvas/tools/yaml-new/layers.yaml @@ -174,7 +174,7 @@ fuzzy: maxDifference=0-2; totalPixels=0-6766 alpha.blending: <<: *global-state-alpha-blending - fuzzy: maxDifference=0-1; totalPixels=0-2440 + fuzzy: maxDifference=0-1; totalPixels=0-2453 alpha.composite: <<: *global-state-alpha-composite fuzzy: maxDifference=0-1; totalPixels=0-5204 diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/webgpu-access.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/webgpu-access.yaml new file mode 100644 index 00000000000..fcf38d1f3d0 --- /dev/null +++ b/tests/wpt/tests/html/canvas/tools/yaml-new/webgpu-access.yaml @@ -0,0 +1,10 @@ +- name: 2d.webgpuaccess.getTextureFormat.rgba8.tentative.https + desc: getTextureFormat() returns RGBA8 or BGRA8 for a typical context + code: | + @assert ctx.getTextureFormat() =~ /^rgba8unorm|bgra8unorm$/; + +- name: 2d.webgpuaccess.getTextureFormat.rgba16f.tentative.https + desc: getTextureFormat() returns RGBA16F for a float16 context + attributes: '{colorSpace: "display-p3", pixelFormat: "float16"}' + code: | + @assert ctx.getTextureFormat() === "rgba16float"; diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-001.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-001.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-001.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-001.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-002.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-002.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-002.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-002.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-003.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-003.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-003.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-003.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-004.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-004.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-004.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-004.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-005.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-005.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-005.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-005.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-006.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-006.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-006.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-006.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-007.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-007.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-007.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-007.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-008.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-008.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-008.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-008.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-009.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-009.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-009.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-009.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-010.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-010.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-010.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-010.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-011.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-011.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-011.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-011.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-012.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-012.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-012.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-012.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-013.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-013.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-013.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-013.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-014.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-014.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-014.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-014.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-015.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-015.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-015.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-015.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-016.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-016.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-016.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-016.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-017.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-017.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-017.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-017.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-018.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-018.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-018.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-018.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-019.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-019.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-019.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-019.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-020.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-020.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-020.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-020.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-021.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-021.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-021.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-021.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-022.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-022.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-022.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-022.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-023.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-023.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-023.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-023.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-024.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-024.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-024.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-024.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-025.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-025.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-025.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-025.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-026.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-026.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-026.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-026.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-027.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-027.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-027.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-027.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-028.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-028.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-028.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-028.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-029.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-029.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-029.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-029.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-030.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-030.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-030.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-030.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-031.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-031.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-031.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-031.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-032.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-032.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-032.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-032.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-033.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-033.html similarity index 100% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-033.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-033.html diff --git a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.tentative.html b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.html similarity index 94% rename from tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.tentative.html rename to tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.html index 92d4a06b1a9..a505de48756 100644 --- a/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.tentative.html +++ b/tests/wpt/tests/html/dom/render-blocking/element-render-blocking-034.html @@ -5,7 +5,7 @@ link rel=expect should allow relative URLs - + -link rel=expect: base URL should be ignored when after link +link rel=expect: base URL should be OK with relative URLs - + + + +link rel=expect: only connected elements are eligible + + + + + +
                                + +
                                + + + +
                                + +
                                + diff --git a/tests/wpt/tests/html/rendering/widgets/field-sizing-textarea.html b/tests/wpt/tests/html/rendering/widgets/field-sizing-textarea.html index f8d90dc659b..114d60c72d0 100644 --- a/tests/wpt/tests/html/rendering/widgets/field-sizing-textarea.html +++ b/tests/wpt/tests/html/rendering/widgets/field-sizing-textarea.html @@ -3,6 +3,10 @@ +

                                + + + + + pXp + XpXpXp + XpXpXp + + + + +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-001.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-001.html new file mode 100644 index 00000000000..63aa9a4da88 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-001.html @@ -0,0 +1,24 @@ + + +<semantics> - mozilla bug 468059 + + + + + + +

                                + + + + pXp + XpXpXp + XpXpXp + + + +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002-ref.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002-ref.html new file mode 100644 index 00000000000..8abdad93dea --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002-ref.html @@ -0,0 +1,12 @@ + +semantics element and legacy rendering rules (reference) + +

                                Empty semantics:

                                +

                                annotation: annotation

                                +

                                annotation-xml: annotation-xml

                                +

                                presentation MathML (no annotations): presentation MathML

                                +

                                content MathML (no annotations): content MathML

                                +

                                presentation MathML ; annotation: presentation MathML

                                +

                                presentation MathML ; annotation-xml: presentation MathML

                                +

                                content MathML ; annotation: content MathML

                                +

                                content MathML ; annotation-xml: content MathML

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002.html new file mode 100644 index 00000000000..62028fb863e --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-002.html @@ -0,0 +1,16 @@ + +semantics element and legacy rendering rules + + + + + +

                                Empty semantics:

                                +

                                annotation: annotation

                                +

                                annotation-xml: annotation-xml

                                +

                                presentation MathML (no annotations): presentation MathML

                                +

                                content MathML (no annotations): content MathML

                                +

                                presentation MathML ; annotation: presentation MathMLannotation

                                +

                                presentation MathML ; annotation-xml: presentation MathMLannotation-xml

                                +

                                content MathML ; annotation: content MathMLannotation

                                +

                                content MathML ; annotation-xml: content MathMLannotation-xml

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003-ref.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003-ref.html new file mode 100644 index 00000000000..7b6e21a3eb8 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003-ref.html @@ -0,0 +1,13 @@ + +semantics element and legacy rendering rules (reference) + +

                                annotation 1: Content MathML

                                +

                                annotation 2: Content MathML

                                +

                                annotation 3: Content MathML

                                +

                                annotation-xml 1: Content MathML

                                +

                                annotation-xml 2: Content MathML

                                +

                                annotation-xml 3: Content MathML

                                +

                                annotation-xml 4: Content MathML

                                +

                                annotation-xml 5: Content MathML

                                +

                                annotation-xml 6: Content MathML

                                +

                                annotation-xml 7: Content MathML

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003.html new file mode 100644 index 00000000000..83572f4c8c3 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-003.html @@ -0,0 +1,17 @@ + +semantics element and legacy rendering rules + + + + + +

                                annotation 1: Content MathMLannotationerrorerror

                                +

                                annotation 2: Content MathML\sin x + 5errorerror

                                +

                                annotation 3: Content MathMLerrorannotationerror

                                +

                                annotation-xml 1: Content MathMLapplication/mathml-presentation+xmlerrorerror

                                +

                                annotation-xml 2: Content MathMLMathML-Presentationerrorerror

                                +

                                annotation-xml 3: Content MathMLimage/svg+xmlerrorerror

                                +

                                annotation-xml 4: Content MathMLSVG1.1errorerror

                                +

                                annotation-xml 5: Content MathMLapplication/xhtml+xml

                                application/xhtml+xml

                                errorerror

                                +

                                annotation-xml 6: Content MathMLtext/html

                                text/html

                                errorerror

                                +

                                annotation-xml 7: Content MathMLerrorannotation-xmlerror

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004-ref.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004-ref.html new file mode 100644 index 00000000000..855d887bbca --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004-ref.html @@ -0,0 +1,41 @@ + + +<semantics> - mozilla bug 512418 (reference) + + +

                                + XpXpXp + + + lcm + ( + a + , + b + ) + + = + + + ( + a + + b + ) + + + gcd + ( + a + , + b + ) + + + + XpXpXp +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004.html new file mode 100644 index 00000000000..17f0f1ecd09 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-004.html @@ -0,0 +1,47 @@ + + +<semantics> - mozilla bug 512418 + + + + + + +

                                + XpXpXp + + + + lcm + ( + a + , + b + ) + + = + + + ( + a + + b + ) + + + gcd + ( + a + , + b + ) + + + + + XpXpXp +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005-ref.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005-ref.html new file mode 100644 index 00000000000..cf722603e1d --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005-ref.html @@ -0,0 +1,11 @@ + +<semantics> - mozilla bug 21479 (reference) + +

                                + + + + ¯ + + +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005.html b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005.html new file mode 100644 index 00000000000..e4fe611c475 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/mrow/semantics-005.html @@ -0,0 +1,15 @@ + +<semantics> - mozilla bug 21479 + + + + + +

                                + + + + ¯ + + +

                                diff --git a/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-1.html b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-1.html new file mode 100644 index 00000000000..9f37cddc398 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-1.html @@ -0,0 +1,64 @@ + + + + Stretchy/Largeop with default fonts + + + + + + + + +

                                + + + ( + + ) + + +

                                +

                                + + + ( + + ) + + +

                                +

                                + + + ( + + ) + + +

                                +

                                + + + ( + + ) + + +

                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-2.html b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-2.html new file mode 100644 index 00000000000..7c43c80acc0 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-2.html @@ -0,0 +1,132 @@ + + + + Stretchy/Largeop with default fonts + + + + + + + + +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + ⫿ + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + + +

                                +

                                + + ⫿ + +

                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-3.html b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-3.html new file mode 100644 index 00000000000..d588b9d4e07 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/operators/stretchy-largeop-with-default-font-3.html @@ -0,0 +1,145 @@ + + + + Stretchy/Largeop with default fonts + + + + + + + + +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + + + +

                                +

                                + + + + ⫿ + + +

                                +

                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ⫿ + +

                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001-ref.html new file mode 100644 index 00000000000..d814944f531 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001-ref.html @@ -0,0 +1,15 @@ + + + + mmultiscript with no scripts (reference) + + + + + base + + + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001.html new file mode 100644 index 00000000000..e55a04e1286 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-001.html @@ -0,0 +1,17 @@ + + + + mmultiscript with no scripts + + + + + + + + + base + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002-ref.html new file mode 100644 index 00000000000..33f12d7cdfa --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002-ref.html @@ -0,0 +1,16 @@ + + + + mmultiscript with mprescripts (reference) + + + + + base + + + + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002.html new file mode 100644 index 00000000000..c5e426008f9 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-002.html @@ -0,0 +1,18 @@ + + + + mmultiscript with mprescripts + + + + + + + + + base + + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003-ref.html new file mode 100644 index 00000000000..daac6b33467 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003-ref.html @@ -0,0 +1,42 @@ + + + + alignment of mmultiscript sub/superscripts + + + + + + + + + + + + + + + + + + +
                                +
                                + + + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003.html b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003.html new file mode 100644 index 00000000000..7de3e98b8ab --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/mmultiscript-003.html @@ -0,0 +1,42 @@ + + + + alignment of mmultiscript sub/superscripts + + + + + + + + + + + + + + + + + + + + +
                                +
                                + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false-ref.html new file mode 100644 index 00000000000..db72d0c5e2f --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false-ref.html @@ -0,0 +1,70 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="false") + + +
                                ` are +//! assigned the corresponding display value from the user agent stylesheet. +//! +//! Every [`Table`] holds an array of [`TableSlot`]. A [`TableSlot`] represents either a cell, a cell +//! location occupied by a cell originating from another place in the table, or is empty. In +//! addition, when there are table model errors, a slot may spanned by more than one cell. +//! +//! During processing, the box tree construction agorithm will also fix up table structure, for +//! instance, creating anonymous rows for lone table cells and putting non-table content into +//! anonymous cells. In addition, flow layout will collect table elements outside of tables and create +//! anonymous tables for them. +//! +//! After processing, box tree construction does a fix up pass on tables, converting rowspan=0 into +//! definite rowspan values and making sure that rowspan and celspan values are not larger than the +//! table itself. Finally, row groups may be reordered to enforce the fact that the first `
                                + + + + + + + + + + + + + + + + +
                                movermunder
                                Over < BaseOver > BaseUnder < BaseUnder > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false.html new file mode 100644 index 00000000000..0d4205410a9 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-false.html @@ -0,0 +1,57 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="false") + + + + + + + + + + + + + + + + + + + + + + +
                                movermunder
                                Over < BaseOver > BaseUnder < BaseUnder > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true-ref.html new file mode 100644 index 00000000000..da1033563eb --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true-ref.html @@ -0,0 +1,70 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="true") + + + + + + + + + + + + + + + + + + + +
                                movermunder
                                Over < BaseOver > BaseUnder < BaseUnder > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true.html new file mode 100644 index 00000000000..aa70d244f33 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munder-mover-align-accent-true.html @@ -0,0 +1,57 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="true") + + + + + + + + + + + + + + + + + + + + + + +
                                movermunder
                                Over < BaseOver > BaseUnder < BaseUnder > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false-ref.html new file mode 100644 index 00000000000..c339149c256 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false-ref.html @@ -0,0 +1,85 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="false") + + + + + + + + + + + + + + + + + + +
                                munderover
                                Over < Base < UnderOver > Base > UnderOver = Under < BaseOver = Under > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false.html new file mode 100644 index 00000000000..2c082612a25 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-false.html @@ -0,0 +1,60 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="false") + + + + + + + + + + + + + + + + + + + + + +
                                munderover
                                Over < Base < UnderOver > Base > UnderOver = Under < BaseOver = Under > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true-ref.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true-ref.html new file mode 100644 index 00000000000..aababcb17bb --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true-ref.html @@ -0,0 +1,85 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="true") + + + + + + + + + + + + + + + + + + +
                                munderover
                                Over < Base < UnderOver > Base > UnderOver = Under < BaseOver = Under > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true.html b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true.html new file mode 100644 index 00000000000..e6578ade523 --- /dev/null +++ b/tests/wpt/tests/mathml/presentation-markup/scripts/munderover-align-accent-true.html @@ -0,0 +1,60 @@ + + + + Horizontal alignment of base with munder/mover scripts (accent="true") + + + + + + + + + + + + + + + + + + + + + +
                                munderover
                                Over < Base < UnderOver > Base > UnderOver = Under < BaseOver = Under > Base
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + diff --git a/tests/wpt/tests/mathml/relations/html5-tree/tabindex-focus-001.tentative.html b/tests/wpt/tests/mathml/relations/html5-tree/tabindex-focus-001.tentative.html new file mode 100644 index 00000000000..2ea0390eabd --- /dev/null +++ b/tests/wpt/tests/mathml/relations/html5-tree/tabindex-focus-001.tentative.html @@ -0,0 +1,34 @@ + +Invalid tabindex + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font-ref.html b/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font-ref.html new file mode 100644 index 00000000000..5c295152ba0 --- /dev/null +++ b/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font-ref.html @@ -0,0 +1,13 @@ + + + + + mo glyph height with default font (reference) + + +
                                + + diff --git a/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font.html b/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font.html new file mode 100644 index 00000000000..262d3b92777 --- /dev/null +++ b/tests/wpt/tests/mathml/relations/text-and-math/mo-glyph-height-with-default-font.html @@ -0,0 +1,52 @@ + + + + + mo glyph height with default font + + + + + + + + | + + f + + ( + x + ) + + + + f + + ( + + x + 0 + + ) + + + + | + + +