diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..db0c44de --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,5 @@ +[alias] +xtask = "run --release --package xtask --" + +[build] +rustflags = ["-Zpolonius=next"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91458c19..da79b3b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - + - name: Install native dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libfontconfig1-dev - name: Install Stable Toolchain uses: dtolnay/rust-toolchain@master with: @@ -35,6 +36,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + - name: Install native dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libfontconfig1-dev - name: Install Stable Toolchain uses: dtolnay/rust-toolchain@master with: @@ -75,7 +78,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - + - name: Install native dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libfontconfig1-dev - name: Install Stable Toolchain uses: dtolnay/rust-toolchain@master with: @@ -106,6 +110,8 @@ jobs: build-ios: runs-on: macos-latest + env: + IPHONEOS_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -122,6 +128,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + - name: Install native dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libfontconfig1-dev - name: Install Stable Toolchain uses: dtolnay/rust-toolchain@master with: @@ -130,3 +138,35 @@ jobs: run: cargo test --package craft_retained --no-run - name: Run Unit Tests run: cargo test --package craft_retained --no-fail-fast --verbose + + integration-tests: + runs-on: windows-latest + env: + CRAFT_RETAINED_TEST: generate-all + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install Stable Toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE_VER }} + + - name: Run Integration Tests + run: | + cargo test --test counter --no-default-features --features="vello_cpu_renderer png" + + - name: Generate Kompari report + if: always() + run: cargo xtask report + + - name: Upload Kompari report + if: always() + uses: actions/upload-artifact@v4 + with: + name: kompari-report + path: | + report.html + crates/craft_retained/tests/current + crates/craft_retained/tests/snapshots \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cb8d8749..db556814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -14,49 +14,52 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" -version = "0.21.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf203f9d3bd8f29f98833d1fbef628df18f759248a547e7e01cfbf63cda36a99" +checksum = "5351dcebb14b579ccab05f288596b2ae097005be7ee50a7c3d4ca9d0d5a66f6a" +dependencies = [ + "uuid", +] [[package]] name = "accesskit_atspi_common" -version = "0.14.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890d241cf51fc784f0ac5ac34dfc847421f8d39da6c7c91a0fcc987db62a8267" +checksum = "842fd8203e6dfcf531d24f5bac792088edfba7d6b35844fead191603fb32a260" dependencies = [ "accesskit", "accesskit_consumer", "atspi-common", + "phf", "serde", - "thiserror 1.0.69", "zvariant", ] [[package]] name = "accesskit_consumer" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db81010a6895d8707f9072e6ce98070579b43b717193d2614014abd5cb17dd43" +checksum = "53cf47daed85312e763fbf85ceca136e0d7abc68e0a7e12abe11f48172bc3b10" dependencies = [ "accesskit", - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] name = "accesskit_macos" -version = "0.22.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0089e5c0ac0ca281e13ea374773898d9354cc28d15af9f0f7394d44a495b575" +checksum = "534bc3fdc89a64a1db3c46b33c198fde2b7c3c7d094e5809c8c8bf2970c18243" dependencies = [ "accesskit", "accesskit_consumer", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", @@ -64,9 +67,9 @@ dependencies = [ [[package]] name = "accesskit_unix" -version = "0.17.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301e55b39cfc15d9c48943ce5f572204a551646700d0e8efa424585f94fec528" +checksum = "90e549dd7c6562b6a2ea807b44726e6241707db054a817dc4c7e2b8d3b39bfac" dependencies = [ "accesskit", "accesskit_atspi_common", @@ -80,23 +83,23 @@ dependencies = [ [[package]] name = "accesskit_windows" -version = "0.29.2" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d63dd5041e49c363d83f5419a896ecb074d309c414036f616dc0b04faca971" +checksum = "eff7009f1a532e917d66970a1e80c965140c6cfbbabbdde3d64e5431e6c78e21" dependencies = [ "accesskit", "accesskit_consumer", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "static_assertions", - "windows 0.61.1", - "windows-core 0.61.2", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] name = "accesskit_winit" -version = "0.29.2" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cfabe59d0eaca7412bfb1f70198dd31e3b0496fee7e15b066f9c36a1a140a0" +checksum = "1fe9a94394896352cc4660ca2288bd4ef883d83238853c038b44070c8f134313" dependencies = [ "accesskit", "accesskit_macos", @@ -108,9 +111,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -119,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -127,9 +130,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -142,23 +145,21 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-activity" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.10.0", + "bitflags 2.11.0", "cc", - "cesu8", - "jni", - "jni-sys", + "jni 0.22.4", "libc", "log", "ndk", "ndk-context", "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -176,6 +177,62 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "arrayref" version = "0.3.9" @@ -217,9 +274,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -229,9 +286,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -243,28 +300,27 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix 1.0.7", + "rustix 1.1.4", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -273,9 +329,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", @@ -286,8 +342,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 0.38.44", - "tracing", + "rustix 1.1.4", ] [[package]] @@ -303,9 +358,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -313,10 +368,10 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.44", + "rustix 1.1.4", "signal-hook-registry", "slab", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -327,9 +382,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -344,20 +399,19 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atspi" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83247582e7508838caf5f316c00791eee0e15c0bf743e6880585b867e16815c" +checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d" dependencies = [ "atspi-common", - "atspi-connection", "atspi-proxies", ] [[package]] name = "atspi-common" -version = "0.9.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33dfc05e7cdf90988a197803bf24f5788f94f7c94a69efa95683e8ffe76cfdfb" +checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d" dependencies = [ "enumflags2", "serde", @@ -370,33 +424,95 @@ dependencies = [ ] [[package]] -name = "atspi-connection" -version = "0.9.0" +name = "atspi-proxies" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4193d51303d8332304056ae0004714256b46b6635a5c556109b319c0d3784938" +checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc" dependencies = [ "atspi-common", - "atspi-proxies", - "futures-lite", + "serde", "zbus", ] [[package]] -name = "atspi-proxies" -version = "0.9.0" +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eebcb9e7e76f26d0bcfd6f0295e1cd1e6f33bedbc5698a971db8dc43d7751c" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ - "atspi-common", - "serde", - "zbus", + "aws-lc-sys", + "zeroize", ] [[package]] -name = "autocfg" -version = "1.4.0" +name = "aws-lc-sys" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] [[package]] name = "base64" @@ -436,11 +552,20 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "serde_core", + "funty", + "radium", + "tap", + "wyz", ] [[package]] @@ -460,18 +585,18 @@ dependencies = [ [[package]] name = "block2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2 0.6.3", + "objc2 0.6.4", ] [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", "async-task", @@ -482,24 +607,25 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ + "bytes", "cfg_aliases", ] [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] @@ -529,9 +655,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "calloop" @@ -539,7 +665,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "log", "polling", "rustix 0.38.44", @@ -561,10 +687,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.22" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -578,9 +705,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -590,39 +717,92 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ + "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", ] +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "clipboard-rs" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4320896621317ada426b440ebb0534c6234d2da9714ac05ae604ea7e2ddc3a5" +checksum = "58c4843457db4cfc367efd4fc554e0f222c9da86359606132adc0db01592b82b" dependencies = [ "clipboard-win", "image", - "objc2 0.6.3", - "objc2-app-kit 0.3.1", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", - "objc2-ui-kit 0.3.1", + "objc2-ui-kit 0.3.2", "windows 0.59.0", "x11rb", ] [[package]] name = "clipboard-win" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" dependencies = [ "error-code", "windows-win", ] +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + [[package]] name = "codespan-reporting" version = "0.12.0" @@ -634,6 +814,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7f99105610438d4b3ee7ae8e453c2990e325c806a14d71e8ea937d584c5289" +dependencies = [ + "bytemuck", +] + [[package]] name = "color" version = "0.3.2" @@ -643,6 +832,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -662,6 +857,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -684,9 +892,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -711,19 +919,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "libc", -] - [[package]] name = "core-graphics-types" version = "0.1.3" @@ -741,8 +936,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.0", + "bitflags 2.11.0", + "core-foundation 0.10.1", "libc", ] @@ -807,7 +1002,7 @@ dependencies = [ "craft_logging", "craft_runtime", "image", - "reqwest", + "reqwest 0.13.2", "tinyvg-rs", ] @@ -817,7 +1012,7 @@ version = "0.1.1" dependencies = [ "accesskit", "accesskit_winit", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "chrono", "clipboard-rs", @@ -826,15 +1021,16 @@ dependencies = [ "craft_renderer", "craft_resource_manager", "craft_runtime", + "craft_undo", "image", - "kurbo", + "libtest-mimic-collect", "open", "parley", "peniko", "pulldown-cmark", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "smallvec", - "smol_str 0.3.4", + "smol_str 0.3.6", "syntect", "taffy", "tinyvg-rs", @@ -856,11 +1052,15 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "craft_undo" +version = "0.1.1" + [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -905,23 +1105,33 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "ctor-lite" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b" +checksum = "e162d0c2e2068eb736b71e5597eff0b9944e6b973cd9f37b6a288ab9bf20e300" [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] @@ -934,12 +1144,12 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dispatch2" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.11.0", + "objc2 0.6.4", ] [[package]] @@ -955,18 +1165,18 @@ dependencies = [ [[package]] name = "dlib" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" dependencies = [ "libloading", ] [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -985,25 +1195,26 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "drm" -version = "0.12.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" +checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "drm-ffi", "drm-fourcc", + "libc", "rustix 0.38.44", ] [[package]] name = "drm-ffi" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" +checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" dependencies = [ "drm-sys", - "rustix 0.38.44", + "rustix 1.1.4", ] [[package]] @@ -1014,20 +1225,32 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" [[package]] name = "drm-sys" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" +checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8" dependencies = [ "libc", - "linux-raw-sys 0.6.5", + "linux-raw-sys 0.9.4", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1039,15 +1262,15 @@ dependencies = [ [[package]] name = "endi" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -1055,9 +1278,9 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", @@ -1072,12 +1295,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1086,20 +1309,26 @@ version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +[[package]] +name = "escape8259" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" + [[package]] name = "euclid" -version = "0.22.11" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" dependencies = [ "num-traits", ] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1164,18 +1393,32 @@ dependencies = [ [[package]] name = "fearless_simd" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb2907d1f08b2b316b9223ced5b0e89d87028ba8deae9764741dba8ff7f3903" +checksum = "76258897e51fd156ee03b6246ea53f3e0eb395d0b327e9961c4fc4c8b2fa151a" + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ - "bytemuck", + "cfg-if", + "libc", + "libredox", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1201,33 +1444,32 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "font-types" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511e2c18a516c666d27867d2f9821f76e7d591f762e9fc41dd6cc5c90fe54b0b" +checksum = "73829a7b5c91198af28a99159b7ae4afbb252fb906159ff7f189f3a2ceaa3df2" dependencies = [ "bytemuck", ] [[package]] name = "fontique" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bbc252c93499b6d3635d692f892a637db0dbb130ce9b32bf20b28e0dcc470b" +checksum = "23358480a54a886d51b306718d5ca743fdfe238e5df38ef650f4e72f29c5d9e9" dependencies = [ - "bytemuck", "hashbrown 0.16.1", - "icu_locale_core", "linebender_resource_handle", "memmap2", - "objc2 0.6.3", + "objc2 0.6.4", "objc2-core-foundation", "objc2-core-text", "objc2-foundation 0.3.2", + "parlance", "read-fonts", "roxmltree", "smallvec", - "windows 0.58.0", - "windows-core 0.58.0", + "windows 0.62.2", + "windows-core 0.62.2", "yeslogic-fontconfig-sys", ] @@ -1275,18 +1517,30 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1294,9 +1548,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-intrusive" @@ -1311,15 +1565,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1330,21 +1584,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", @@ -1352,47 +1606,68 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] +[[package]] +name = "gallery" +version = "0.1.0" +dependencies = [ + "craft_renderer", + "craft_retained", + "util", +] + [[package]] name = "gethostname" -version = "0.4.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "libc", - "windows-targets 0.48.5", + "rustix 1.1.4", + "windows-link 0.2.1", ] [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "r-efi 5.3.0", + "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -1425,35 +1700,18 @@ dependencies = [ "gl_generator", ] -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.10.0", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.10.0", -] - [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ + "ash", + "hashbrown 0.16.1", "log", "presser", - "thiserror 1.0.69", - "windows 0.58.0", + "thiserror 2.0.18", + "windows 0.62.2", ] [[package]] @@ -1462,7 +1720,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -1473,7 +1731,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -1484,9 +1742,9 @@ checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" [[package]] name = "guillotiere" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" dependencies = [ "euclid", "svg_fmt", @@ -1494,9 +1752,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -1525,11 +1783,11 @@ dependencies = [ [[package]] name = "harfrust" -version = "0.3.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c020db12c71d8a12a3fe7607873cade3a01a6287e29d540c8723276221b9d8" +checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "core_maths", "read-fonts", @@ -1542,8 +1800,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", ] @@ -1558,11 +1814,17 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1578,12 +1840,11 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1616,21 +1877,39 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1638,11 +1917,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http", "hyper", "hyper-util", @@ -1651,7 +1929,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.11", ] [[package]] @@ -1672,14 +1949,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -1688,7 +1964,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.9", + "socket2", "system-configuration", "tokio", "tower-service", @@ -1697,141 +1973,166 @@ dependencies = [ ] [[package]] -name = "icu_collections" -version = "1.5.0" +name = "iana-time-zone" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec 0.10.4", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", ] [[package]] -name = "icu_locale_core" +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", - "litemap 0.8.0", - "serde", - "tinystr 0.8.1", - "writeable 0.6.2", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" dependencies = [ - "displaydoc", - "litemap 0.7.5", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", ] [[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr 0.7.6", - "zerovec 0.10.4", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "icu_locid_transform_data" -version = "1.5.1" +name = "icu_locale_data" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" +checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831" [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec 0.10.4", + "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr 0.7.6", - "zerovec 0.10.4", + "zerotrie", + "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", + "serde", "stable_deref_trait", - "tinystr 0.7.6", - "writeable 0.5.5", + "writeable", "yoke", "zerofrom", - "zerovec 0.10.4", + "zerotrie", + "zerovec", ] [[package]] -name = "icu_provider_macros" -version = "1.5.0" +name = "icu_segmenter" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +checksum = "a807a7488f3f758629ae86d99d9d30dce24da2fb2945d74c80a4f4a62c71db73" dependencies = [ - "proc-macro2", - "quote", - "syn", + "icu_collections", + "icu_locale", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "utf8_iter", + "zerovec", ] +[[package]] +name = "icu_segmenter_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebbb7321d9e21d25f5660366cb6c08201d0175898a3a6f7a41ee9685af21c80" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1840,9 +2141,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1850,41 +2151,63 @@ dependencies = [ [[package]] name = "image" -version = "0.25.8" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", "moxcms", "num-traits", - "png 0.18.0", + "png 0.18.1", "tiff", "zune-core", "zune-jpeg", ] +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + [[package]] name = "indexmap" -version = "2.9.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.1", + "rayon", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" dependencies = [ "memchr", "serde", @@ -1909,11 +2232,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jni" @@ -1924,35 +2253,89 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1969,11 +2352,11 @@ dependencies = [ [[package]] name = "keyboard-types" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6e0f18953c66af118a70064505bd3780a226d65b06553b7293fb8933067967" +checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "serde", ] @@ -1994,11 +2377,56 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kompari" +version = "0.1.0" +source = "git+https://github.com/linebender/kompari.git?rev=63476ab8a6413cd5add210b76c1d2d671dd67212#63476ab8a6413cd5add210b76c1d2d671dd67212" +dependencies = [ + "bytemuck", + "color 0.2.4", + "log", + "oxipng", + "png 0.17.16", + "rayon", + "thiserror 2.0.18", + "walkdir", +] + +[[package]] +name = "kompari-html" +version = "0.1.0" +source = "git+https://github.com/linebender/kompari.git?rev=63476ab8a6413cd5add210b76c1d2d671dd67212#63476ab8a6413cd5add210b76c1d2d671dd67212" +dependencies = [ + "axum", + "base64", + "chrono", + "imagesize", + "kompari", + "maud", + "rayon", + "serde", + "tokio", +] + +[[package]] +name = "kompari-tasks" +version = "0.1.0" +source = "git+https://github.com/linebender/kompari.git?rev=63476ab8a6413cd5add210b76c1d2d671dd67212#63476ab8a6413cd5add210b76c1d2d671dd67212" +dependencies = [ + "clap", + "humansize", + "indicatif", + "kompari", + "kompari-html", + "rayon", + "termcolor", +] + [[package]] name = "kurbo" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" +checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb" dependencies = [ "arrayvec", "euclid", @@ -2011,37 +2439,96 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.172" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libdeflate-sys" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "72753e0008ea87963d2f0770042d0df7abe51fafbb8dcaf618ac440f2f1fec0a" +dependencies = [ + "cc", +] + +[[package]] +name = "libdeflater" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ee41cf6fb1bb6030dfb59ffb7bc01ab26aade44142084c87f0fc7a1658fe71" +dependencies = [ + "libdeflate-sys", +] [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-link 0.2.1", ] [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", - "redox_syscall 0.5.12", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libtest-mimic" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33" +dependencies = [ + "anstream", + "anstyle", + "clap", + "escape8259", +] + +[[package]] +name = "libtest-mimic-collect" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a30974da57f2ec4e94399f6036f7d6c02128e96b780760b46efde9cd058e3ec" +dependencies = [ + "ctor", + "libtest-mimic", + "libtest-mimic-collect-macro", +] + +[[package]] +name = "libtest-mimic-collect-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6eeb2525f5cee3328f83ac5ba57977b458e5ed7b54eeebd52709445f156a3c9" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2062,12 +2549,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "linux-raw-sys" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -2075,38 +2556,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] -name = "litemap" -version = "0.7.5" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru-slab" @@ -2123,17 +2603,45 @@ dependencies = [ "libc", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "maud" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8156733e27020ea5c684db5beac5d1d611e1272ab17901a49466294b84fc217e" +dependencies = [ + "itoa", + "maud_macros", +] + +[[package]] +name = "maud_macros" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7261b00f3952f617899bc012e3dbd56e4f0110a038175929fa5d18e5a19913ca" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] @@ -2149,11 +2657,11 @@ dependencies = [ [[package]] name = "metal" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block", "core-graphics-types 0.2.0", "foreign-types 0.5.0", @@ -2170,9 +2678,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -2180,39 +2688,48 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "moxcms" -version = "0.7.8" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ "num-traits", "pxfm", ] +[[package]] +name = "multiwindow" +version = "0.1.0" +dependencies = [ + "craft_renderer", + "craft_retained", + "util", +] + [[package]] name = "naga" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c" +checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases", "codespan-reporting", "half", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "hexf-parse", "indexmap", "libm", @@ -2221,15 +2738,15 @@ dependencies = [ "once_cell", "rustc-hash 1.1.0", "spirv", - "thiserror 2.0.12", + "thiserror 2.0.18", "unicode-ident", ] [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -2248,8 +2765,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.10.0", - "jni-sys", + "bitflags 2.11.0", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -2269,37 +2786,23 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", + "jni-sys 0.3.1", ] [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-traits" @@ -2313,18 +2816,19 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2332,6 +2836,12 @@ dependencies = [ "syn", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "objc" version = "0.2.7" @@ -2359,9 +2869,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] @@ -2372,7 +2882,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -2384,21 +2894,23 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.10.0", - "block2 0.6.1", + "bitflags 2.11.0", + "block2 0.6.2", "libc", - "objc2 0.6.3", - "objc2-cloud-kit 0.3.1", - "objc2-core-data 0.3.1", + "objc2 0.6.4", + "objc2-cloud-kit 0.3.2", + "objc2-core-data 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-core-image 0.3.1", + "objc2-core-image 0.3.2", + "objc2-core-text", + "objc2-core-video", "objc2-foundation 0.3.2", - "objc2-quartz-core 0.3.1", + "objc2-quartz-core 0.3.2", ] [[package]] @@ -2407,7 +2919,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location 0.2.2", @@ -2416,12 +2928,12 @@ dependencies = [ [[package]] name = "objc2-cloud-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.11.0", + "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2442,7 +2954,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2450,12 +2962,12 @@ dependencies = [ [[package]] name = "objc2-core-data" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.11.0", + "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2465,20 +2977,20 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dispatch2", - "objc2 0.6.3", + "objc2 0.6.4", ] [[package]] name = "objc2-core-graphics" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dispatch2", - "objc2 0.6.3", + "objc2 0.6.4", "objc2-core-foundation", "objc2-io-surface", ] @@ -2497,11 +3009,11 @@ dependencies = [ [[package]] name = "objc2-core-image" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "objc2 0.6.3", + "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2519,11 +3031,11 @@ dependencies = [ [[package]] name = "objc2-core-location" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0f75792558aa9d618443bbb5db7426a7a0b6fddf96903f86ef9ad02e135740" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" dependencies = [ - "objc2 0.6.3", + "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2533,8 +3045,23 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", ] [[package]] @@ -2549,7 +3076,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "dispatch", "libc", @@ -2562,21 +3089,21 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.10.0", - "block2 0.6.1", + "bitflags 2.11.0", + "block2 0.6.2", "libc", - "objc2 0.6.3", + "objc2 0.6.4", "objc2-core-foundation", ] [[package]] name = "objc2-io-surface" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.11.0", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -2598,7 +3125,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2610,7 +3137,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2619,12 +3146,12 @@ dependencies = [ [[package]] name = "objc2-quartz-core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.11.0", + "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", ] @@ -2645,7 +3172,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit 0.2.2", @@ -2662,22 +3189,23 @@ dependencies = [ [[package]] name = "objc2-ui-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.10.0", - "block2 0.6.1", - "objc2 0.6.3", - "objc2-cloud-kit 0.3.1", - "objc2-core-data 0.3.1", + "bitflags 2.11.0", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-cloud-kit 0.3.2", + "objc2-core-data 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-core-image 0.3.1", - "objc2-core-location 0.3.1", + "objc2-core-image 0.3.2", + "objc2-core-location 0.3.2", + "objc2-core-text", "objc2-foundation 0.3.2", - "objc2-quartz-core 0.3.1", - "objc2-user-notifications 0.3.1", + "objc2-quartz-core 0.3.2", + "objc2-user-notifications 0.3.2", ] [[package]] @@ -2697,7 +3225,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location 0.2.2", @@ -2706,19 +3234,25 @@ dependencies = [ [[package]] name = "objc2-user-notifications" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3f5ec77a81d9e0c5a0b32159b0cb143d7086165e79708351e02bf37dfc65cd" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ - "objc2 0.6.3", + "objc2 0.6.4", "objc2-foundation 0.3.2", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "onig" @@ -2726,7 +3260,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", "once_cell", "onig_sys", @@ -2744,9 +3278,9 @@ dependencies = [ [[package]] name = "open" -version = "5.3.2" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ "is-wsl", "libc", @@ -2755,11 +3289,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "foreign-types 0.3.2", "libc", @@ -2781,15 +3315,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" dependencies = [ "cc", "libc", @@ -2799,27 +3333,19 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.48" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" dependencies = [ + "libc", "libredox", ] -[[package]] -name = "ordered-channel" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95be4d57809897b5a7539fc15a7dfe0e84141bc3dfaa2e9b1b27caa90acf61ab" -dependencies = [ - "crossbeam-channel", -] - [[package]] name = "ordered-float" -version = "4.6.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", ] @@ -2835,18 +3361,30 @@ dependencies = [ ] [[package]] -name = "overload" -version = "0.1.1" +name = "owned_ttf_parser" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] [[package]] -name = "owned_ttf_parser" -version = "0.25.0" +name = "oxipng" +version = "9.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +checksum = "26c613f0f566526a647c7473f6a8556dbce22c91b13485ee4b4ec7ab648e4973" dependencies = [ - "ttf-parser", + "bitvec", + "crossbeam-channel", + "filetime", + "indexmap", + "libdeflater", + "log", + "rayon", + "rgb", + "rustc-hash 2.1.2", + "zopfli", ] [[package]] @@ -2857,9 +3395,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2867,30 +3405,49 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.12", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] +[[package]] +name = "parlance" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6937eda350acc1a5d05872c3cbf99fe78619c269096e2be3d4a350058639d5" + [[package]] name = "parley" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada5338c3a9794af7342e6f765b6e78740db37378aced034d7bf72c96b94ed94" +checksum = "d6c00ec192e1a402861526eff91a4b4690a2e5a17a4ae2deb772d72b49daf868" dependencies = [ "accesskit", "fontique", "harfrust", "hashbrown 0.16.1", + "icu_normalizer", + "icu_properties", + "icu_segmenter", "linebender_resource_handle", + "parlance", + "parley_data", "skrifa", - "swash", +] + +[[package]] +name = "parley_data" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232313eddc02ac27f015e8f8eeb7facce8a896116df7e3eda1bfd9f600a9a39d" +dependencies = [ + "icu_properties", ] [[package]] @@ -2907,12 +3464,12 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "peniko" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c76095c9a636173600478e0373218c7b955335048c2bcd12dc6a79657649d8" +checksum = "9a2b6aadb221872732e87d465213e9be5af2849b0e8cc5300a8ba98fffa2e00a" dependencies = [ "bytemuck", - "color", + "color 0.3.2", "kurbo", "linebender_resource_handle", "smallvec", @@ -2920,24 +3477,67 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", @@ -2946,9 +3546,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -2958,9 +3558,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", "fastrand", @@ -2973,15 +3573,21 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plist" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64", "indexmap", - "quick-xml 0.37.5", + "quick-xml 0.38.4", "serde", "time", ] @@ -3001,11 +3607,11 @@ dependencies = [ [[package]] name = "png" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "crc32fast", "fdeflate", "flate2", @@ -3023,34 +3629,44 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 0.38.44", - "tracing", - "windows-sys 0.59.0", + "rustix 1.1.4", + "windows-sys 0.61.2", ] [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3072,49 +3688,68 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", +] + [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" [[package]] name = "pulldown-cmark" -version = "0.13.0" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +checksum = "7c3a14896dfa883796f1cb410461aef38810ea05f2b2c33c5aded3649095fdad" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "memchr", "unicase", ] [[package]] name = "pxfm" -version = "0.1.25" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" -dependencies = [ - "num-traits", -] +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" [[package]] name = "quick-error" @@ -3124,9 +3759,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", "serde", @@ -3134,28 +3769,28 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.5" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustls", - "socket2 0.5.9", - "thiserror 2.0.12", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -3163,20 +3798,21 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ + "aws-lc-rs", "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand", "ring", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -3184,32 +3820,44 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.9", + "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -3233,18 +3881,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "range-alloc" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" [[package]] name = "raw-window-handle" @@ -3254,9 +3902,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -3264,9 +3912,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -3274,9 +3922,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.35.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", "core_maths", @@ -3294,18 +3942,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3314,9 +3971,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "renderdoc-sys" @@ -3326,9 +3983,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64", "bytes", @@ -3350,12 +4007,49 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", "quinn", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tokio-native-tls", @@ -3367,7 +4061,15 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.0", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", ] [[package]] @@ -3378,7 +4080,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3401,9 +4103,18 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] [[package]] name = "rustix" @@ -3411,7 +4122,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3420,47 +4131,87 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "web-time", + "zeroize", ] [[package]] -name = "rustls" -version = "0.23.27" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni 0.21.1", + "log", "once_cell", - "ring", - "rustls-pki-types", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", "rustls-webpki", - "subtle", - "zeroize", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] [[package]] -name = "rustls-pki-types" -version = "1.12.0" +name = "rustls-platform-verifier-android" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "web-time", - "zeroize", -] +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3468,15 +4219,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3489,11 +4240,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3523,12 +4274,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", + "bitflags 2.11.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -3536,14 +4287,20 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -3576,14 +4333,26 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", ] [[package]] @@ -3626,24 +4395,47 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "skrifa" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", "read-fonts", @@ -3651,18 +4443,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -3679,7 +4468,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -3709,9 +4498,9 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498b0a27f93ef1402f20eefacfaa1691272ac4eca1cdc8c596cb0a245d6cbf5" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" dependencies = [ "borsh", "serde_core", @@ -3719,53 +4508,43 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "softbuffer" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "as-raw-xcb-connection", "bytemuck", - "cfg_aliases", - "core-graphics 0.24.0", "drm", "fastrand", - "foreign-types 0.5.0", "js-sys", - "log", "memmap2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "ndk", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", "raw-window-handle", - "redox_syscall 0.5.12", - "rustix 0.38.44", + "redox_syscall 0.5.18", + "rustix 1.1.4", "tiny-xlib", + "tracing", "wasm-bindgen", "wayland-backend", "wayland-client", "wayland-sys", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "x11rb", ] @@ -3775,14 +4554,14 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -3796,6 +4575,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -3808,22 +4593,11 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" -[[package]] -name = "swash" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47846491253e976bdd07d0f9cc24b7daf24720d11309302ccbbc6e6b6e53550a" -dependencies = [ - "skrifa", - "yazi", - "zeno", -] - [[package]] name = "syn" -version = "2.0.101" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -3867,7 +4641,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.18", "walkdir", "yaml-rust", ] @@ -3876,17 +4650,17 @@ dependencies = [ name = "syntect_dumper" version = "0.1.0" dependencies = [ - "reqwest", + "reqwest 0.12.28", "syntect", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3903,9 +4677,8 @@ dependencies = [ [[package]] name = "taffy" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ba83ebaf2954d31d05d67340fd46cebe99da2b7133b0dd68d70c65473a437b" +version = "0.10.0" +source = "git+https://github.com/AustinMReppert/taffy?rev=41af7ddf5806dcf67a3d702fcbe37b340a5cc8b8#41af7ddf5806dcf67a3d702fcbe37b340a5cc8b8" dependencies = [ "arrayvec", "grid", @@ -3913,17 +4686,23 @@ dependencies = [ "slotmap", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" -version = "3.20.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.4.2", "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix 1.1.4", + "windows-sys 0.61.2", ] [[package]] @@ -3955,11 +4734,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.18", ] [[package]] @@ -3975,9 +4754,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -3986,19 +4765,18 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "tiff" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" dependencies = [ "fax", "flate2", @@ -4010,30 +4788,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -4079,29 +4857,20 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec 0.10.4", -] - -[[package]] -name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", - "zerovec 0.11.2", + "serde_core", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4123,24 +4892,24 @@ dependencies = [ [[package]] name = "tokio" -version = "1.48.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", - "socket2 0.6.0", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -4159,9 +4928,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -4169,9 +4938,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -4180,9 +4949,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -4193,26 +4962,39 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.25.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "toml_parser", + "winnow 1.0.0", +] + +[[package]] +name = "toml_parser" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +dependencies = [ + "winnow 1.0.0", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -4221,15 +5003,16 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "futures-util", "http", @@ -4255,10 +5038,11 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4266,9 +5050,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -4277,9 +5061,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -4298,9 +5082,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -4337,20 +5121,19 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "uds_windows" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "ui-events" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a57da61c5700db75d28822c56068295055ec216996560af57a5d4a457914d34" +version = "0.3.0" +source = "git+https://github.com/endoli/ui-events?rev=d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7#d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7" dependencies = [ "dpi", "keyboard-types", @@ -4359,9 +5142,8 @@ dependencies = [ [[package]] name = "ui-events-winit" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ef6b086ceb9e4bbf0148e494959b18cf08de7604f8d8e958a94e73fc2d531e" +version = "0.3.0" +source = "git+https://github.com/endoli/ui-events?rev=d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7#d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7" dependencies = [ "ui-events", "web-time", @@ -4370,27 +5152,33 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -4400,27 +5188,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "util" version = "0.1.0" @@ -4431,6 +5220,17 @@ dependencies = [ "tracing-web", ] +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "js-sys", + "serde_core", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -4445,54 +5245,63 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vello" -version = "0.6.0" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.8.0" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", "futures-intrusive", "log", "peniko", - "png 0.17.16", + "png 0.18.1", "skrifa", "static_assertions", - "thiserror 2.0.12", + "thiserror 2.0.18", "vello_encoding", "vello_shaders", "wgpu", ] +[[package]] +name = "vello_api" +version = "0.0.7" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" +dependencies = [ + "bytemuck", + "peniko", +] + [[package]] name = "vello_common" -version = "0.0.4" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.0.7" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", "fearless_simd", - "hashbrown 0.15.5", + "guillotiere", + "hashbrown 0.16.1", "log", "peniko", - "png 0.17.16", + "png 0.18.1", "skrifa", "smallvec", + "thiserror 2.0.18", ] [[package]] name = "vello_cpu" -version = "0.0.4" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.0.7" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", - "crossbeam-channel", - "ordered-channel", - "rayon", - "thread_local", + "hashbrown 0.16.1", + "vello_api", "vello_common", ] [[package]] name = "vello_encoding" -version = "0.6.0" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.8.0" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", "guillotiere", @@ -4503,14 +5312,14 @@ dependencies = [ [[package]] name = "vello_hybrid" -version = "0.0.4" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.0.7" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", - "guillotiere", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "log", - "thiserror 2.0.12", + "thiserror 2.0.18", + "vello_api", "vello_common", "vello_sparse_shaders", "wgpu", @@ -4518,20 +5327,20 @@ dependencies = [ [[package]] name = "vello_shaders" -version = "0.6.0" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.8.0" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" dependencies = [ "bytemuck", "log", "naga", - "thiserror 2.0.12", + "thiserror 2.0.18", "vello_encoding", ] [[package]] name = "vello_sparse_shaders" -version = "0.0.4" -source = "git+https://github.com/linebender/vello.git?rev=459e0a7b1fa328d8b6adeea0c31a2069621a85d0#459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +version = "0.0.7" +source = "git+https://github.com/linebender/vello.git?rev=5796226bfafd75fb121e938536ff74bb80a6114f#5796226bfafd75fb121e938536ff74bb80a6114f" [[package]] name = "version_check" @@ -4560,63 +5369,56 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen" -version = "0.2.100" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" +name = "wasm-bindgen" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4624,35 +5426,69 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "wayland-backend" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" +checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.44", + "rustix 1.1.4", "scoped-tls", "smallvec", "wayland-sys", @@ -4660,12 +5496,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.10" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" +checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" dependencies = [ - "bitflags 2.10.0", - "rustix 0.38.44", + "bitflags 2.11.0", + "rustix 1.1.4", "wayland-backend", "wayland-scanner", ] @@ -4676,29 +5512,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.10" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" +checksum = "4b3298683470fbdc6ca40151dfc48c8f2fd4c41a26e13042f801f85002384091" dependencies = [ - "rustix 0.38.44", + "rustix 1.1.4", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.32.8" +version = "0.32.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" +checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -4706,11 +5542,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" +checksum = "d392fc283a87774afc9beefcd6f931582bb97fe0e6ced0b306a62cb1d026527c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4719,11 +5555,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" +checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4732,20 +5568,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.6" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" dependencies = [ "proc-macro2", - "quick-xml 0.37.5", + "quick-xml 0.39.2", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.6" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" dependencies = [ "dlib", "log", @@ -4755,9 +5591,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" dependencies = [ "js-sys", "wasm-bindgen", @@ -4774,41 +5610,50 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.26.11" +name = "webpki-root-certs" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ - "webpki-roots 1.0.0", + "rustls-pki-types", ] [[package]] -name = "webpki-roots" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +name = "website" +version = "0.1.0" dependencies = [ - "rustls-pki-types", + "console_error_panic_hook", + "craft_retained", + "open", + "reqwest 0.13.2", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", + "tracing-web", + "util", + "web-sys", ] [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "26.0.1" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b6ff82bbf6e9206828e1a3178e851f8c20f1c9028e74dd3a8090741ccd5798" +checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", - "bitflags 2.10.0", + "bitflags 2.11.0", + "bytemuck", "cfg-if", "cfg_aliases", "document-features", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "js-sys", "log", "naga", @@ -4828,17 +5673,18 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "26.0.1" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f62f1053bd28c2268f42916f31588f81f64796e2ff91b81293515017ca8bd9" +checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.11.0", + "bytemuck", "cfg_aliases", "document-features", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "indexmap", "log", "naga", @@ -4849,7 +5695,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.18", "wgpu-core-deps-apple", "wgpu-core-deps-emscripten", "wgpu-core-deps-wasm", @@ -4860,51 +5706,51 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf" +checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d" +checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03b9f9e1a50686d315fc6debe4980cc45cd37b0e919351917df494e8fdc8885" +checksum = "12a2cf578ce8d7d50d0e63ddc2345c7dcb599f6eb90b888813406ea78b9b7010" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720a5cb9d12b3d337c15ff0e24d3e97ed11490ff3f7506e7f3d98c68fa5d6f14" +checksum = "68ca976e72b2c9964eb243e281f6ce7f14a514e409920920dcda12ae40febaae" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "26.0.6" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d0e67224cc7305b3b4eb2cc57ca4c4c3afc665c1d1bee162ea806e19c47bdd" +checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.10.0", + "bitflags 2.11.0", "block", "bytemuck", "cfg-if", @@ -4912,10 +5758,9 @@ dependencies = [ "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", - "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "js-sys", "khronos-egl", "libc", @@ -4925,6 +5770,7 @@ dependencies = [ "naga", "ndk-sys", "objc", + "once_cell", "ordered-float", "parking_lot", "portable-atomic", @@ -4934,67 +5780,34 @@ dependencies = [ "raw-window-handle", "renderdoc-sys", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.18", "wasm-bindgen", "web-sys", "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] name = "wgpu-types" -version = "26.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2" +checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "js-sys", "log", - "thiserror 2.0.12", "web-sys", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-sys 0.61.2", ] [[package]] @@ -5004,42 +5817,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" dependencies = [ "windows-core 0.59.0", - "windows-targets 0.53.0", + "windows-targets 0.53.5", ] [[package]] name = "windows" -version = "0.61.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.61.2", + "windows-core 0.62.2", "windows-future", - "windows-link 0.1.1", "windows-numerics", ] [[package]] name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.58.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core 0.62.2", ] [[package]] @@ -5049,47 +5848,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ "windows-implement 0.59.0", - "windows-interface 0.59.1", + "windows-interface", "windows-result 0.3.4", "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-targets 0.53.5", ] [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link 0.1.1", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-implement 0.60.2", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-future" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.1", + "windows-core 0.62.2", + "windows-link 0.2.1", "windows-threading", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.59.0" @@ -5103,20 +5891,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -5125,9 +5902,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -5136,9 +5913,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" @@ -5148,32 +5925,23 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-numerics" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.1", + "windows-core 0.62.2", + "windows-link 0.2.1", ] [[package]] name = "windows-registry" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" -dependencies = [ - "windows-link 0.1.1", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-result" -version = "0.2.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -5182,17 +5950,16 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.1.3", ] [[package]] -name = "windows-strings" -version = "0.1.0" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -5201,16 +5968,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.1.3", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.2.1", ] [[package]] @@ -5240,6 +6007,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -5264,21 +6040,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -5297,27 +6058,28 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows-threading" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.2.1", ] [[package]] @@ -5335,12 +6097,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5349,9 +6105,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -5359,12 +6115,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5373,9 +6123,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -5383,12 +6133,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5397,9 +6141,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -5409,9 +6153,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -5419,12 +6163,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5433,9 +6171,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -5443,12 +6181,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5457,9 +6189,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -5467,12 +6199,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5481,9 +6207,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -5491,12 +6217,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5505,27 +6225,27 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" -version = "0.30.12" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.10.0", + "bitflags 2.11.0", "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", - "core-graphics 0.23.2", + "core-graphics", "cursor-icon", "dpi", "js-sys", @@ -5563,33 +6283,109 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "winnow" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" dependencies = [ - "bitflags 2.10.0", + "memchr", ] [[package]] -name = "write16" -version = "1.0.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] [[package]] -name = "writeable" -version = "0.5.5" +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -5597,6 +6393,15 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -5610,30 +6415,30 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", "libloading", "once_cell", - "rustix 0.38.44", + "rustix 1.1.4", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "xcursor" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" [[package]] name = "xkbcommon-dl" @@ -5641,7 +6446,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dlib", "log", "once_cell", @@ -5656,9 +6461,18 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.26" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "clap", + "kompari", + "kompari-tasks", +] [[package]] name = "yaml-rust" @@ -5669,12 +6483,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "yazi" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" - [[package]] name = "yeslogic-fontconfig-sys" version = "6.0.0" @@ -5688,11 +6496,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5700,9 +6507,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -5712,9 +6519,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.7.1" +version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68" +checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" dependencies = [ "async-broadcast", "async-executor", @@ -5730,14 +6537,16 @@ dependencies = [ "futures-core", "futures-lite", "hex", - "nix", + "libc", "ordered-stream", + "rustix 1.1.4", "serde", "serde_repr", "tracing", "uds_windows", - "windows-sys 0.59.0", - "winnow", + "uuid", + "windows-sys 0.61.2", + "winnow 0.7.15", "zbus_macros", "zbus_names", "zvariant", @@ -5745,9 +6554,9 @@ dependencies = [ [[package]] name = "zbus-lockstep" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22426b1bc2aca91de97772506f0655fa373448e6010d79d5d5880915c388409" +checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863" dependencies = [ "zbus_xml", "zvariant", @@ -5755,9 +6564,9 @@ dependencies = [ [[package]] name = "zbus-lockstep-macros" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100ffec29ed51859052f4563061abe35557acb56ba574510571f8398efc70a29" +checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0" dependencies = [ "proc-macro2", "quote", @@ -5769,9 +6578,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.7.1" +version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a" +checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5784,49 +6593,41 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.2.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" dependencies = [ "serde", - "static_assertions", - "winnow", + "winnow 0.7.15", "zvariant", ] [[package]] name = "zbus_xml" -version = "5.0.2" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589e9a02bfafb9754bb2340a9e3b38f389772684c63d9637e76b1870377bec29" +checksum = "441a0064125265655bccc3a6af6bef56814d9277ac83fce48b1cd7e160b80eac" dependencies = [ - "quick-xml 0.36.2", + "quick-xml 0.38.4", "serde", - "static_assertions", "zbus_names", "zvariant", ] -[[package]] -name = "zeno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" - [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -5856,75 +6657,96 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerotrie" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ + "displaydoc", "yoke", "zerofrom", - "zerovec-derive", ] [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ + "serde", + "yoke", "zerofrom", + "zerovec-derive", ] [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + [[package]] name = "zune-core" -version = "0.4.12" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" [[package]] name = "zune-jpeg" -version = "0.4.21" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] [[package]] name = "zvariant" -version = "5.5.3" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d30786f75e393ee63a21de4f9074d4c038d52c5b1bb4471f955db249f9dffb1" +checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" dependencies = [ "endi", "enumflags2", "serde", - "winnow", + "winnow 0.7.15", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.5.3" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75fda702cd42d735ccd48117b1630432219c0e9616bf6cb0f8350844ee4d9580" +checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5935,14 +6757,13 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" dependencies = [ "proc-macro2", "quote", "serde", - "static_assertions", "syn", - "winnow", + "winnow 0.7.15", ] diff --git a/Cargo.toml b/Cargo.toml index 385e4f2a..2f5a0d24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,21 @@ resolver = "2" members = [ "crates/craft_retained", "crates/craft_logger", + "xtask", "examples/util", "examples/counter_retained", + "examples/multiwindow", "examples/pointer_events", "examples/text", "examples/jsframeworkbench", - "crates/syntect_dumper", "crates/craft_renderer", "crates/craft_primitives", "crates/craft_resource_manager", "crates/craft_runtime", + "examples/gallery", + "crates/syntect_dumper", + "crates/craft_renderer", + "crates/craft_primitives", + "crates/craft_resource_manager", + "crates/craft_runtime", + "crates/craft_undo", + "website", ] [workspace.package] @@ -27,18 +36,18 @@ debug = true #debug = false [workspace.dependencies] -reqwest = { version = "0.12.19", default-features = false } +reqwest = { version = "0.13.1", default-features = false } tracing = { version = "0.1.41" } tracing-subscriber = {version = "0.3.19"} [workspace.dependencies.peniko] -version = "0.5.0" +version = "0.6.0" default-features = false features = ["std"] [workspace.dependencies.kurbo] -version = "0.12.0" +version = "0.13.0" default-features = false features = ["std"] @@ -48,12 +57,12 @@ default-features = false features = [] [workspace.dependencies.tokio] -version = "1.48.0" +version = "1.51.0" default-features = false features = ["sync", "time"] [workspace.dependencies.image] -version = "0.25.8" +version = "0.25.10" default-features = false features = [] @@ -68,9 +77,9 @@ default-features = false features = ["std"] [workspace.dependencies.cfg-if] -version = "1.0.1" +version = "1.0.4" [workspace.dependencies.winit] -version = "0.30.12" +version = "0.30.13" default-features = false -features = [] \ No newline at end of file +features = [] diff --git a/README.md b/README.md index 4e087b7b..0887a74c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,71 @@ # 📜 Craft [![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](./LICENSE) [![Discord](https://img.shields.io/discord/1382383100562243746?logo=discord&logoColor=%23ffffff&labelColor=%236A7EC2&color=%237389D8)](https://discord.gg/Atb8nuAub2) + +Craft is a library for creating desktops user interfaces. craft_retained provides platform independent widgets. + + +## Example + +```rust +use std::cell::RefCell; +use std::rc::Rc; + +use craft_retained::elements::{Container, Element, Text, Window}; +use craft_retained::events::ui_events::pointer::PointerButton; +use craft_retained::style::{AlignItems, FlexDirection, JustifyContent}; +use craft_retained::{Color, CraftOptions, pct, px, rgb}; + +fn create_button(label: &str, base_color: Color, delta: i64, state: Rc>, count_text: Text) -> Container { + let border_color = rgb(0, 0, 0); + Container::new() + .border_width(px(1), px(2), px(3), px(4)) + .border_color(border_color, border_color, border_color, border_color) + .border_radius((10.0, 10.0), (10.0, 10.0), (10.0, 10.0), (10.0, 10.0)) + .padding(px(15), px(30), px(15), px(30)) + .justify_content(Some(JustifyContent::Center)) + .background_color(base_color) + .on_pointer_button_up(Rc::new(move |event, pointer_button_event| { + if pointer_button_event.button == Some(PointerButton::Primary) { + *state.borrow_mut() += delta; + count_text.clone().text(&format!("Count: {}", state.borrow())); + event.prevent_propagate(); + } + })) + .push(Text::new(label).font_size(24.0).color(Color::WHITE).selectable(false)) +} + +fn main() { + let count = Rc::new(RefCell::new(0)); + let count_text = Text::new(&format!("Count: {}", count.borrow())); + + Window::new() + .flex_direction(FlexDirection::Column) + .justify_content(Some(JustifyContent::Center)) + .align_items(Some(AlignItems::Center)) + .width(pct(100)) + .height(pct(100)) + .gap(px(20), px(20)) + .push(count_text.clone()) + .push({ + Container::new() + .gap(px(20), px(20)) + .push(create_button( + "-", + rgb(244, 67, 54), + -1, + count.clone(), + count_text.clone(), + )) + .push(create_button( + "+", + rgb(76, 175, 80), + 1, + count.clone(), + count_text.clone(), + )) + }); + + craft_retained::craft_main(CraftOptions::basic("Counter")); +} +``` \ No newline at end of file diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md new file mode 100644 index 00000000..08092ea5 --- /dev/null +++ b/STYLE_GUIDE.md @@ -0,0 +1,110 @@ +# Order Within a File + +```rust +//! Module documentation + +// Extern crates (rare in modern Rust) +extern crate some_extern_crate; + +// Re-exports and imports. +// Grouped by visibility and crate. +// Sorted alphabetically. +pub use crate::somecrate::*; +pub(crate) use crate::foo::bar; + +use std::fmt; + +use third_party::crate; + +use crate::foo::bar; + +use super::baz; + +// Module declarations +mod internal; +pub mod public_api; + +// Constants / statics. +pub const MAX: usize = 100; +pub(crate) const INTERNAL_MAX: usize = 50; + +// Type aliases +type MyType = u32; + +// Structs / Enums + +pub struct PublicStruct { + pub field: u32, + pub(crate) crate_field: u32, + pub(super) super_field: u32, + private_field: u32, +} + +pub(crate) struct CrateStruct { + pub field: u32, + pub(crate) crate_field: u32, + pub(super) super_field: u32, + private_field: u32, +} + +struct PrivateStruct { + pub field: u32, + pub(crate) crate_field: u32, + pub(super) super_field: u32, + private_field: u32, +} + +// Traits + +pub trait MyTrait { + fn do_something(&self); +} + +// Impls + +impl MyTrait for PublicStruct { + fn do_something(&self) { + // ... + } +} + +impl PublicStruct { + + pub fn new() -> Self { + Self { + field: 0, + crate_field: 0, + super_field: 0, + private_field: 0, + } + } + + pub(crate) fn crate_only(&self) {} + + pub(super) fn super_only(&self) {} + + fn private_helper(&self) {} +} + +/// Functions + +pub fn public_function() {} + +pub(crate) fn crate_function() {} + +pub(super) fn super_function() {} + +fn private_function() {} + +// Tests + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} +``` \ No newline at end of file diff --git a/crates/craft_logger/src/lib.rs b/crates/craft_logger/src/lib.rs index 563a190b..be6f469a 100644 --- a/crates/craft_logger/src/lib.rs +++ b/crates/craft_logger/src/lib.rs @@ -1,3 +1 @@ -pub use tracing::{debug, error, info, warn, Level}; - -pub use tracing::span; +pub use tracing::{Level, debug, error, info, span, warn}; diff --git a/crates/craft_primitives/src/color.rs b/crates/craft_primitives/src/color.rs index 4be84cc0..3cef8b50 100644 --- a/crates/craft_primitives/src/color.rs +++ b/crates/craft_primitives/src/color.rs @@ -1,2 +1,2 @@ -pub use peniko::color::palette; pub use peniko::Color; +pub use peniko::color::palette; diff --git a/crates/craft_primitives/src/geometry/borders.rs b/crates/craft_primitives/src/geometry/borders.rs index 9ee4feb9..8c3b7e21 100644 --- a/crates/craft_primitives/src/geometry/borders.rs +++ b/crates/craft_primitives/src/geometry/borders.rs @@ -1,7 +1,7 @@ -use kurbo::{Arc, BezPath, PathEl, Point, Rect, Shape, Vec2}; - use std::f64::consts::{FRAC_PI_2, PI}; use std::ops::Add; + +use kurbo::{Arc, BezPath, PathEl, Point, Rect, Shape, Vec2}; pub const TOP_LEFT: usize = 0; pub const TOP_RIGHT: usize = 1; pub const BOTTOM_RIGHT: usize = 2; @@ -56,6 +56,7 @@ pub struct CssRoundedRect { corners_arcs: [[Option; 4]; 4], background_arcs: [Option; 4], + background_inner_arcs: [Option; 4], widths: [f64; 4], } @@ -72,6 +73,7 @@ impl CssRoundedRect { intersect_angles: [Vec2::default(); 4], corners_arcs: [[None; 4]; 4], background_arcs: [None; 4], + background_inner_arcs: [None; 4], widths, corners: [ Point::new(rect.x0, rect.y0), @@ -88,8 +90,7 @@ impl CssRoundedRect { let width_y = css_rounded_rect.widths[CORNER_VERTICAL_SIDE[corner]]; let is_sharp = is_inner_radius_sharp(width_x, outer_radius.x, width_y, outer_radius.y); if !is_sharp { - css_rounded_rect.inner_radii[corner] = - Vec2::new(outer_radius.x - width_x, outer_radius.y - width_y); + css_rounded_rect.inner_radii[corner] = Vec2::new(outer_radius.x - width_x, outer_radius.y - width_y); } let inner_radius = css_rounded_rect.inner_radii[corner]; @@ -107,19 +108,126 @@ impl CssRoundedRect { std::mem::swap(&mut side_for_radius_x, &mut side_for_radius_y); } - let outer_sweep_angle = - intersect_angle(outer_x, outer_y, side_for_radius_x, side_for_radius_y); - let inner_sweep_angle = - intersect_angle(inner_x, inner_y, side_for_radius_x, side_for_radius_y); + let outer_sweep_angle = intersect_angle(outer_x, outer_y, side_for_radius_x, side_for_radius_y); + let inner_sweep_angle = intersect_angle(inner_x, inner_y, side_for_radius_x, side_for_radius_y); - css_rounded_rect.intersect_angles[corner] = - Vec2::new(inner_sweep_angle, outer_sweep_angle); + css_rounded_rect.intersect_angles[corner] = Vec2::new(inner_sweep_angle, outer_sweep_angle); } css_rounded_rect.compute_arcs(); css_rounded_rect } + pub fn get_outline(&self) -> BezPath { + let mut outline_path = BezPath::new(); + + for corner in CORNERS { + if let Some(arc) = &self.background_arcs[corner] { + let arc_path = arc.to_path(0.1); + if corner == TOP_LEFT { + // For the very first segment, we MoveTo the start of the arc + outline_path.extend(arc_path); + } else { + // For subsequent corners, we LineTo the start of the arc to close the gaps + extend_path_with_arc(&mut outline_path, &arc_path); + } + } else { + // If there is no arc (sharp corner), move or line to the corner point + let p = self.corners[corner]; + if corner == TOP_LEFT { + outline_path.move_to(p); + } else { + outline_path.line_to(p); + } + } + } + + outline_path.close_path(); + outline_path + } + + pub fn get_inline(&self) -> BezPath { + let mut outline_path = BezPath::new(); + + for corner in CORNERS { + if let Some(arc) = &self.background_inner_arcs[corner] { + let arc_path = arc.to_path(0.1); + if corner == TOP_LEFT { + // For the very first segment, we MoveTo the start of the arc + outline_path.extend(arc_path); + } else { + // For subsequent corners, we LineTo the start of the arc to close the gaps + extend_path_with_arc(&mut outline_path, &arc_path); + } + } else { + // If there is no arc (sharp corner), move or line to the corner point + let p = self.corners[corner]; + if corner == TOP_LEFT { + outline_path.move_to(p); + } else { + outline_path.line_to(p); + } + } + } + + outline_path.close_path(); + outline_path + } + + /// Get an outline with a radius relative to the outline. + pub fn get_outline_with_radius(&self, radius: f64) -> BezPath { + let mut box_shadow_arcs: [Option; 4] = [None; 4]; + + for corner in CORNERS { + let outer_radius = self.outer_radii[corner]; + let radius_sign = CORNER_RADIUS_SIGN[corner]; + + let outer_radius = Vec2::new(radius_sign.x * outer_radius.x, radius_sign.y * outer_radius.y); + + if is_outer_radius_sharp(outer_radius) { + continue; + } + + let center = self.corners[corner].add(outer_radius); + + let box_shadow_arc = Arc::new( + center, + self.outer_radii[corner] + Vec2::new(radius, radius), + CORNER_START_ANGLES[corner], + FRAC_PI_2, + 0.0, + ); + box_shadow_arcs[corner] = Some(box_shadow_arc); + } + + let mut outline_path = BezPath::new(); + + for corner in CORNERS { + if let Some(arc) = &box_shadow_arcs[corner] { + let arc_path = arc.to_path(0.1); + if corner == TOP_LEFT { + // For the very first segment, we MoveTo the start of the arc + outline_path.extend(arc_path); + } else { + // For subsequent corners, we LineTo the start of the arc to close the gaps + extend_path_with_arc(&mut outline_path, &arc_path); + } + } else { + // If there is no arc (sharp corner), move or line to the corner point + let sign = CORNER_RADIUS_SIGN[corner]; + let p = self.corners[corner] + Vec2::new(-sign.x * radius, -sign.y * radius); + if corner == TOP_LEFT { + outline_path.move_to(p); + } else { + outline_path.line_to(p); + } + } + } + + outline_path.close_path(); + outline_path + } + fn compute_arcs(&mut self) { for corner in CORNERS { let outer_radius = self.outer_radii[corner]; @@ -127,14 +235,8 @@ impl CssRoundedRect { let radius_sign = CORNER_RADIUS_SIGN[corner]; - let outer_radius = Vec2::new( - radius_sign.x * outer_radius.x, - radius_sign.y * outer_radius.y, - ); - let inner_radius = Vec2::new( - radius_sign.x * inner_radius.x, - radius_sign.y * inner_radius.y, - ); + let outer_radius = Vec2::new(radius_sign.x * outer_radius.x, radius_sign.y * outer_radius.y); + let inner_radius = Vec2::new(radius_sign.x * inner_radius.x, radius_sign.y * inner_radius.y); if is_outer_radius_sharp(outer_radius) { continue; @@ -168,9 +270,18 @@ impl CssRoundedRect { 0.0, ); + let background_inner_arc = Arc::new( + center, + self.inner_radii[corner], + CORNER_START_ANGLES[corner], + FRAC_PI_2, + 0.0, + ); + self.corners_arcs[corner][0] = Some(outside_1st_arc); self.corners_arcs[corner][1] = Some(outside_2nd_arc); self.background_arcs[corner] = Some(background_arc); + self.background_inner_arcs[corner] = Some(background_inner_arc); if is_outer_radius_sharp(inner_radius) { continue; @@ -216,7 +327,7 @@ impl CssRoundedRect { let mut current_arc = FIRST_ARC; if let Some(arc) = &self.corners_arcs[corner][current_arc] { - path.extend(&arc.to_path(0.01)); + path.extend(&arc.to_path(0.1)); } else { path.move_to(rect_corner); } @@ -224,7 +335,7 @@ impl CssRoundedRect { current_arc = NEXT_ARC[current_arc]; if let Some(arc) = &self.corners_arcs[next_corner][current_arc] { - extend_path_with_arc(&mut path, &arc.to_path(0.01)); + extend_path_with_arc(&mut path, &arc.to_path(0.1)); } else { path.line_to(next_rect_corner); } @@ -232,34 +343,28 @@ impl CssRoundedRect { current_arc = NEXT_ARC[current_arc]; if let Some(arc) = &self.corners_arcs[next_corner][current_arc] { - extend_path_with_arc(&mut path, &arc.to_path(0.01)); + extend_path_with_arc(&mut path, &arc.to_path(0.1)); } else { let offset = CORNER_RADIUS_SIGN[next_corner]; let horizontal_side = CORNER_HORIZONTAL_SIDE[next_corner]; let vertical_side = CORNER_VERTICAL_SIDE[next_corner]; let horizontal_width = self.widths[horizontal_side]; let vertical_width = self.widths[vertical_side]; - let inside_corner = next_rect_corner.add(Vec2::new( - horizontal_width * offset.x, - vertical_width * offset.y, - )); + let inside_corner = next_rect_corner.add(Vec2::new(horizontal_width * offset.x, vertical_width * offset.y)); path.line_to(inside_corner); } current_arc = NEXT_ARC[current_arc]; if let Some(arc) = &self.corners_arcs[corner][current_arc] { - extend_path_with_arc(&mut path, &arc.to_path(0.01)); + extend_path_with_arc(&mut path, &arc.to_path(0.1)); } else { let offset = CORNER_RADIUS_SIGN[corner]; let horizontal_side = CORNER_HORIZONTAL_SIDE[corner]; let vertical_side = CORNER_VERTICAL_SIDE[corner]; let horizontal_width = self.widths[horizontal_side]; let vertical_width = self.widths[vertical_side]; - let inside_corner = rect_corner.add(Vec2::new( - horizontal_width * offset.x, - vertical_width * offset.y, - )); + let inside_corner = rect_corner.add(Vec2::new(horizontal_width * offset.x, vertical_width * offset.y)); path.line_to(inside_corner); } path.close_path(); @@ -273,19 +378,12 @@ impl CssRoundedRect { let box_height = self.height(); let f_top_x = box_width / (self.outer_radii[TOP_LEFT].x + self.outer_radii[TOP_RIGHT].x); - let f_bottom_x = - box_width / (self.outer_radii[BOTTOM_LEFT].x + self.outer_radii[BOTTOM_RIGHT].x); + let f_bottom_x = box_width / (self.outer_radii[BOTTOM_LEFT].x + self.outer_radii[BOTTOM_RIGHT].x); - let f_left_y = - box_height / (self.outer_radii[BOTTOM_LEFT].y + self.outer_radii[TOP_LEFT].y); - let f_right_y = - box_height / (self.outer_radii[BOTTOM_RIGHT].y + self.outer_radii[TOP_RIGHT].y); + let f_left_y = box_height / (self.outer_radii[BOTTOM_LEFT].y + self.outer_radii[TOP_LEFT].y); + let f_right_y = box_height / (self.outer_radii[BOTTOM_RIGHT].y + self.outer_radii[TOP_RIGHT].y); - let radius_scale = f_top_x - .min(f_left_y) - .min(f_bottom_x) - .min(f_right_y) - .min(1.0); + let radius_scale = f_top_x.min(f_left_y).min(f_bottom_x).min(f_right_y).min(1.0); for radius in &mut self.outer_radii { *radius *= radius_scale; @@ -310,12 +408,7 @@ impl CssRoundedRect { } /// Calculate the angle of intersection between the quarter-ellipse and a line from the border point to the corner point. -fn intersect_angle( - top_left_radius_x: f64, - top_left_radius_y: f64, - top_width: f64, - right_width: f64, -) -> f64 { +fn intersect_angle(top_left_radius_x: f64, top_left_radius_y: f64, top_width: f64, right_width: f64) -> f64 { // 1. Set up the equations and solve for the intersection point using the quadratic formula. // 2. To get the angle, we use the parametric equation of the ellipse, solving for the angle. @@ -383,10 +476,11 @@ impl CssRectPathIter { if let Some(iter) = &mut self.current_corner_iter { if let Some(el) = iter.next() { // Turn MoveTo into LineTo except for the first corner - if self.current_corner != 1 && matches!(el, PathEl::MoveTo(_)) { - if let PathEl::MoveTo(p) = el { - return Some(PathEl::LineTo(p)); - } + if self.current_corner != 1 + && matches!(el, PathEl::MoveTo(_)) + && let PathEl::MoveTo(p) = el + { + return Some(PathEl::LineTo(p)); } return Some(el); } else { @@ -489,10 +583,7 @@ impl Shape for CssRoundedRect { let border_radius = self.outer_radii[corner]; let sign = CORNER_RADIUS_SIGN[corner]; let corner_point = self.corners[corner]; - let border_point = corner_point.add(Vec2::new( - border_radius.x * sign.x, - border_radius.y * sign.y, - )); + let border_point = corner_point.add(Vec2::new(border_radius.x * sign.x, border_radius.y * sign.y)); let quarter_ellipse_bounds = Rect::from_points(corner_point, border_point); if quarter_ellipse_bounds.contains(p) && arc.contains(p) { return 0; @@ -519,9 +610,10 @@ fn is_outer_radius_sharp(radii: Vec2) -> bool { #[cfg(test)] mod tests { - use super::*; use std::f64::consts::FRAC_PI_2; + use super::*; + const EPS: f64 = 1e-9; #[test] diff --git a/crates/craft_primitives/src/geometry/element_box.rs b/crates/craft_primitives/src/geometry/element_box.rs index d59257e7..16c63981 100644 --- a/crates/craft_primitives/src/geometry/element_box.rs +++ b/crates/craft_primitives/src/geometry/element_box.rs @@ -1,4 +1,5 @@ use kurbo::Affine; + use crate::geometry::{Border, Margin, Padding, Point, Rectangle, Size}; /// An element's box roughly analogous to CSS's box-model. @@ -19,7 +20,10 @@ impl ElementBox { } pub fn margin_rectangle_position(&self) -> Point { - Point::new(self.position.x - self.margin.left as f64, self.position.y - self.margin.top as f64) + Point::new( + self.position.x - self.margin.left as f64, + self.position.y - self.margin.top as f64, + ) } pub fn margin_rectangle_size(&self) -> Size { @@ -111,6 +115,11 @@ impl ElementBox { let content_position = self.content_rectangle_position(); let content_size = self.content_rectangle_size(); - Rectangle::new(content_position.x as f32, content_position.y as f32, content_size.width, content_size.height) + Rectangle::new( + content_position.x as f32, + content_position.y as f32, + content_size.width, + content_size.height, + ) } } diff --git a/crates/craft_primitives/src/geometry/mod.rs b/crates/craft_primitives/src/geometry/mod.rs index 8ac00cb6..ffead4b9 100644 --- a/crates/craft_primitives/src/geometry/mod.rs +++ b/crates/craft_primitives/src/geometry/mod.rs @@ -1,19 +1,19 @@ +pub use kurbo::{Affine, BezPath, Shape, Vec2}; + +pub use crate::geometry::element_box::ElementBox; +pub use crate::geometry::point::{Point, PointConverter}; +pub use crate::geometry::rectangle::Rectangle; +pub use crate::geometry::size::Size; +pub use crate::geometry::trblrectangle::TrblRectangle; + pub mod borders; + mod element_box; mod point; mod rectangle; mod size; mod trblrectangle; -pub use element_box::ElementBox; -pub use point::Point; -pub use point::PointConverter; -pub use rectangle::Rectangle; -pub use size::Size; -pub use trblrectangle::TrblRectangle; - pub type Border = TrblRectangle; pub type Padding = TrblRectangle; pub type Margin = TrblRectangle; - -pub use kurbo::Affine; \ No newline at end of file diff --git a/crates/craft_primitives/src/geometry/point.rs b/crates/craft_primitives/src/geometry/point.rs index 94ce34c0..de02fdca 100644 --- a/crates/craft_primitives/src/geometry/point.rs +++ b/crates/craft_primitives/src/geometry/point.rs @@ -1,5 +1,4 @@ use dpi::PhysicalPosition; - pub use kurbo::Point; /// A “Point-converter” extension trait. diff --git a/crates/craft_primitives/src/geometry/rectangle.rs b/crates/craft_primitives/src/geometry/rectangle.rs index a2b8904b..bfd9df63 100644 --- a/crates/craft_primitives/src/geometry/rectangle.rs +++ b/crates/craft_primitives/src/geometry/rectangle.rs @@ -1,7 +1,7 @@ -use crate::geometry::Point; -use peniko::kurbo; use dpi; +use crate::geometry::Point; + /// A structure representing a rectangle in 2D space. #[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Rectangle { @@ -25,6 +25,7 @@ impl Rectangle { /// # Returns /// /// `true` if the rectangle contains the point, `false` otherwise. + #[inline(always)] pub fn contains(&self, point: &Point) -> bool { point.x as f32 >= self.left() && point.x as f32 <= self.right() @@ -65,30 +66,31 @@ impl Rectangle { } /// Returns the position of the top-left corner of the rectangle. + #[inline(always)] pub fn position(&self) -> Point { Point::new(self.x as f64, self.y as f64) } /// Returns the y-coordinate of the top edge of the rectangle. - #[inline] + #[inline(always)] pub fn top(&self) -> f32 { self.y } /// Returns the x-coordinate of the right edge of the rectangle. - #[inline] + #[inline(always)] pub fn right(&self) -> f32 { self.x + self.width } /// Returns the y-coordinate of the bottom edge of the rectangle. - #[inline] + #[inline(always)] pub fn bottom(&self) -> f32 { self.y + self.height } /// Returns the x-coordinate of the left edge of the rectangle. - #[inline] + #[inline(always)] pub fn left(&self) -> f32 { self.x } @@ -118,6 +120,20 @@ impl Rectangle { None } } + + #[inline(always)] + pub fn intersects(&self, other: &Rectangle) -> bool { + self.x < other.right() && self.right() > other.x && self.y < other.bottom() && self.bottom() > other.y + } + + pub fn expand(&self, radius: f32) -> Self { + Rectangle::new( + self.x - radius, + self.y - radius, + self.width + radius, + self.height + radius, + ) + } } /*impl From> for Rectangle { @@ -141,4 +157,4 @@ impl From for Rectangle { } } } -*/ \ No newline at end of file +*/ diff --git a/crates/craft_primitives/src/geometry/size.rs b/crates/craft_primitives/src/geometry/size.rs index ac09e1fb..24fdc692 100644 --- a/crates/craft_primitives/src/geometry/size.rs +++ b/crates/craft_primitives/src/geometry/size.rs @@ -18,6 +18,7 @@ impl Size { /// # Returns /// /// A `Size` instance with the specified width and height. + #[inline(always)] pub fn new(width: T, height: T) -> Self { Self { width, height } } @@ -37,4 +38,4 @@ impl Size { Self::new(size.width, size.height) } } -*/ \ No newline at end of file +*/ diff --git a/crates/craft_primitives/src/geometry/trblrectangle.rs b/crates/craft_primitives/src/geometry/trblrectangle.rs index 8cfac69b..f06a3c24 100644 --- a/crates/craft_primitives/src/geometry/trblrectangle.rs +++ b/crates/craft_primitives/src/geometry/trblrectangle.rs @@ -1,6 +1,5 @@ #[derive(Copy, Clone, Debug, Default, PartialEq)] -pub struct TrblRectangle -{ +pub struct TrblRectangle { pub top: T, pub right: T, pub bottom: T, @@ -11,6 +10,7 @@ impl TrblRectangle where T: Copy + PartialEq, { + #[inline(always)] pub const fn new(top: T, right: T, bottom: T, left: T) -> Self { Self { top, @@ -19,6 +19,7 @@ where left, } } + pub const fn new_all(value: T) -> Self { Self { top: value, diff --git a/crates/craft_primitives/src/hit_testable.rs b/crates/craft_primitives/src/hit_testable.rs index 343f1c93..b19d8ac9 100644 --- a/crates/craft_primitives/src/hit_testable.rs +++ b/crates/craft_primitives/src/hit_testable.rs @@ -1,11 +1,9 @@ use crate::geometry::Point; pub trait HitTestable { - fn hit_test(&self, point: &Point) -> bool; fn has_event_handlers(&self) -> bool; fn id(&self) -> usize; - -} \ No newline at end of file +} diff --git a/crates/craft_primitives/src/lib.rs b/crates/craft_primitives/src/lib.rs index 4963d84c..640f43b2 100644 --- a/crates/craft_primitives/src/lib.rs +++ b/crates/craft_primitives/src/lib.rs @@ -1,10 +1,9 @@ -mod color; +pub use color::{Color, palette}; +pub use color_brush::ColorBrush; +pub use hit_testable::HitTestable; pub mod geometry; + +mod color; mod color_brush; mod hit_testable; - -pub use color::Color; -pub use color::palette; -pub use color_brush::ColorBrush; -pub use hit_testable::HitTestable; \ No newline at end of file diff --git a/crates/craft_renderer/Cargo.toml b/crates/craft_renderer/Cargo.toml index 2ba7f41b..cd4686b9 100644 --- a/crates/craft_renderer/Cargo.toml +++ b/crates/craft_renderer/Cargo.toml @@ -13,35 +13,35 @@ vello_hybrid_renderer_webgl = ["wgpu/webgl"] [dependencies.vello] git = "https://github.com/linebender/vello.git" -rev = "459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +rev = "5796226bfafd75fb121e938536ff74bb80a6114f" default-features = false features = ["wgpu"] optional = true [dependencies.vello_cpu] git = "https://github.com/linebender/vello.git" -rev = "459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +rev = "5796226bfafd75fb121e938536ff74bb80a6114f" optional = true -features = ["multithreading"] +features = [] [dependencies.vello_hybrid] git = "https://github.com/linebender/vello.git" -rev = "459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +rev = "5796226bfafd75fb121e938536ff74bb80a6114f" default-features = false features = ["default"] optional = true [dependencies.vello_common] git = "https://github.com/linebender/vello.git" -rev = "459e0a7b1fa328d8b6adeea0c31a2069621a85d0" +rev = "5796226bfafd75fb121e938536ff74bb80a6114f" optional = true [dependencies.softbuffer] -version = "0.4.6" +version = "0.4.8" optional = true [dependencies.wgpu] -version = "26.0.1" +version = "28.0.0" default-features = false features = ["wgsl", "vulkan", "dx12"] optional = true diff --git a/crates/craft_renderer/src/blank_renderer.rs b/crates/craft_renderer/src/blank_renderer.rs index 95cdcfb9..c28731f5 100644 --- a/crates/craft_renderer/src/blank_renderer.rs +++ b/crates/craft_renderer/src/blank_renderer.rs @@ -1,10 +1,13 @@ -use crate::renderer::{RenderList, Renderer}; -use craft_primitives::geometry::Rectangle; -use craft_primitives::Color; -use craft_resource_manager::ResourceManager; use std::any::Any; use std::sync::Arc; +use craft_primitives::Color; +use craft_primitives::geometry::Rectangle; +use craft_resource_manager::ResourceManager; + +use crate::render_list::RenderList; +use crate::renderer::Renderer; + pub struct BlankRenderer; impl Renderer for BlankRenderer { @@ -19,17 +22,17 @@ impl Renderer for BlankRenderer { fn resize_surface(&mut self, _width: f32, _height: f32) {} fn surface_set_clear_color(&mut self, _color: Color) {} + fn as_any_mut(&mut self) -> &mut dyn Any { self } - + fn prepare_render_list<'a>( &mut self, _render_list: &mut RenderList, _resource_manager: Arc, _window: Rectangle, ) { - } fn submit(&mut self, _resource_manager: Arc) {} diff --git a/crates/craft_renderer/src/brush.rs b/crates/craft_renderer/src/brush.rs new file mode 100644 index 00000000..137e0865 --- /dev/null +++ b/crates/craft_renderer/src/brush.rs @@ -0,0 +1,16 @@ +use peniko::{BrushRef, Color, Gradient}; + +#[derive(Clone, Debug)] +pub enum Brush { + Color(Color), + Gradient(Gradient), +} + +impl<'a> From<&'a Brush> for BrushRef<'a> { + fn from(brush: &'a Brush) -> Self { + match brush { + Brush::Color(color) => Self::Solid(*color), + Brush::Gradient(gradient) => Self::Gradient(gradient), + } + } +} diff --git a/crates/craft_renderer/src/color.rs b/crates/craft_renderer/src/color.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/craft_renderer/src/helpers.rs b/crates/craft_renderer/src/helpers.rs new file mode 100644 index 00000000..343bceed --- /dev/null +++ b/crates/craft_renderer/src/helpers.rs @@ -0,0 +1,30 @@ +#[cfg(any( + feature = "vello_cpu_renderer", + feature = "vello_hybrid_renderer", + feature = "vello_hybrid_renderer_webgl" +))] +use vello_common::paint::PaintType; + +#[cfg(any( + feature = "vello_cpu_renderer", + feature = "vello_hybrid_renderer", + feature = "vello_hybrid_renderer_webgl" +))] +use crate::Brush; + +#[cfg(any( + feature = "vello_cpu_renderer", + feature = "vello_hybrid_renderer", + feature = "vello_hybrid_renderer_webgl" +))] +pub(crate) fn brush_to_paint(brush: &Brush) -> PaintType { + match brush { + Brush::Color(color) => PaintType::Solid(*color), + Brush::Gradient(gradient) => PaintType::Gradient(gradient.clone()), + } +} + +#[cfg(feature = "vello_cpu_renderer")] +pub const fn rgba_to_encoded_u32(r: u32, g: u32, b: u32, a: u32) -> u32 { + b | (g << 8) | (r << 16) | (a << 24) +} diff --git a/crates/craft_renderer/src/image_adapter.rs b/crates/craft_renderer/src/image_adapter.rs index 50f2f149..d37e3f0b 100644 --- a/crates/craft_renderer/src/image_adapter.rs +++ b/crates/craft_renderer/src/image_adapter.rs @@ -1,6 +1,7 @@ -use craft_resource_manager::image::ImageResource; use std::sync::Arc; +use craft_resource_manager::image::ImageResource; + pub struct ImageAdapter { image: Arc, } diff --git a/crates/craft_renderer/src/lib.rs b/crates/craft_renderer/src/lib.rs index de8aed24..8220d85d 100644 --- a/crates/craft_renderer/src/lib.rs +++ b/crates/craft_renderer/src/lib.rs @@ -1,4 +1,4 @@ -pub mod color; +pub mod brush; #[allow(clippy::module_inception)] pub mod renderer; @@ -10,14 +10,22 @@ pub mod vello; pub mod vello_cpu; pub mod blank_renderer; +pub(crate) mod helpers; mod image_adapter; +pub mod render_command; +mod render_list; +mod renderer_type; +mod screenshot; +mod sort_commands; +mod target_item; +pub mod text_renderer_data; pub(crate) mod tinyvg_helpers; #[cfg(feature = "vello_hybrid_renderer")] pub mod vello_hybrid; -pub mod text_renderer_data; -mod renderer_type; -pub use renderer::Brush; -pub use renderer::RenderCommand; -pub use renderer::RenderList; +pub use brush::Brush; +pub use render_command::RenderCommand; +pub use render_list::RenderList; pub use renderer_type::RendererType; +pub use screenshot::Screenshot; +pub use target_item::TargetItem; diff --git a/crates/craft_renderer/src/render_command.rs b/crates/craft_renderer/src/render_command.rs new file mode 100644 index 00000000..cbabf051 --- /dev/null +++ b/crates/craft_renderer/src/render_command.rs @@ -0,0 +1,89 @@ +use std::cell::RefCell; +use std::rc::Weak; + +use peniko::Color; + +use craft_primitives::geometry::{Affine, BezPath, Rectangle, Vec2}; + +use craft_resource_manager::ResourceId; + +use crate::Brush; +use crate::text_renderer_data::{TextData, TextScroll}; + +#[derive(Clone)] +pub enum RenderCommand { + SetTransform(SetTransformCmd), + DrawRect(DrawRectCmd), + DrawRectOutline(DrawRectOutlineCmd), + DrawImage(DrawImageCmd), + DrawTinyVg(DrawTinyVgCmd), + DrawText(DrawTextCmd), + PushLayer(PushLayerCmd), + PopLayer, + FillBezPath(FillBezPathCmd), + StartOverlay, + EndOverlay, + BoxShadowCmd(BoxShadowCmd), +} + +#[derive(Clone)] +pub struct SetTransformCmd { + pub transform: Affine, +} + +#[derive(Clone)] +pub struct DrawRectCmd { + pub rect: Rectangle, + pub color: Color, +} + +#[derive(Clone)] +pub struct DrawRectOutlineCmd { + pub rect: Rectangle, + pub outline_color: Color, + pub thickness: f64, +} + +#[derive(Clone)] +pub struct DrawImageCmd { + pub rect: Rectangle, + pub resource_id: ResourceId, +} + +#[derive(Clone)] +pub struct DrawTinyVgCmd { + pub rect: Rectangle, + pub resource_id: ResourceId, + pub override_color: Option, +} + +#[derive(Clone)] +pub struct DrawTextCmd { + pub rect: Rectangle, + pub data: Weak>, + pub text_scroll: Option, + pub show_cursor: bool, +} + +#[derive(Clone)] +pub enum PushLayerCmd { + BezPath(BezPath), + Rect(Rectangle), +} + +#[derive(Clone)] +pub struct FillBezPathCmd { + pub path: BezPath, + pub brush: Brush, +} + +#[derive(Clone)] +pub struct BoxShadowCmd { + pub inset: bool, + pub offset: Vec2, + pub outline: BezPath, + pub path: BezPath, + pub blur_radius: f64, + pub color: Color, + pub border_box: Rectangle, +} diff --git a/crates/craft_renderer/src/render_list.rs b/crates/craft_renderer/src/render_list.rs new file mode 100644 index 00000000..cc4dfe55 --- /dev/null +++ b/crates/craft_renderer/src/render_list.rs @@ -0,0 +1,186 @@ +use std::cell::RefCell; +use std::rc::Weak; + +use peniko::Color; + +use craft_primitives::geometry::{Affine, BezPath, Rectangle, Shape}; +use craft_resource_manager::ResourceId; + +use crate::render_command::{BoxShadowCmd, DrawImageCmd, DrawRectCmd, DrawRectOutlineCmd, DrawTextCmd, DrawTinyVgCmd, FillBezPathCmd, PushLayerCmd, SetTransformCmd}; +use crate::sort_commands::SortedCommands; +use crate::text_renderer_data::{TextData, TextScroll}; +use crate::{Brush, RenderCommand, TargetItem}; + +pub struct RenderList { + current_overlay_depth: u64, + pub targets: Vec, + pub commands: Vec, + /// Stores a sorted list of render command handles. This gets set in `Renderer::sort_render_list`. + pub overlay: SortedCommands, + cull: Option, +} + +impl Default for RenderList { + fn default() -> Self { + Self::new() + } +} + +impl RenderList { + pub fn new() -> Self { + Self { + current_overlay_depth: 0, + targets: Vec::new(), + commands: Vec::new(), + overlay: SortedCommands { children: vec![] }, + cull: None, + } + } + + pub fn clear(&mut self) { + self.targets.clear(); + self.commands.clear(); + self.overlay.children.clear(); + } + + #[inline(always)] + pub fn set_transform(&mut self, transform: Affine) { + self.commands + .push(RenderCommand::SetTransform(SetTransformCmd { transform })); + } + + #[inline(always)] + pub fn draw_rect(&mut self, rect: Rectangle, color: Color) { + if let Some(cull) = &self.cull + && !cull.intersects(&rect) + { + return; + } + self.commands.push(RenderCommand::DrawRect(DrawRectCmd { rect, color })); + } + + #[inline(always)] + pub fn push_hit_testable(&mut self, id: u64, bounding_box: Rectangle) { + if let Some(cull) = &self.cull + && !cull.intersects(&bounding_box) + { + return; + } + self.targets + .push(TargetItem::new(id, bounding_box, self.current_overlay_depth)); + } + + #[inline(always)] + pub fn draw_rect_outline(&mut self, rect: Rectangle, outline_color: Color, thickness: f64) { + if let Some(cull) = &self.cull + && !cull.intersects(&rect) + { + return; + } + self.commands.push(RenderCommand::DrawRectOutline(DrawRectOutlineCmd { + rect, + outline_color, + thickness, + })); + } + + #[inline(always)] + pub fn fill_bez_path(&mut self, path: BezPath, brush: Brush) { + if let Some(cull) = &self.cull + && !cull.intersects(&Rectangle::from_kurbo(path.bounding_box())) + { + return; + } + self.commands + .push(RenderCommand::FillBezPath(FillBezPathCmd { path, brush })); + } + + #[inline(always)] + pub fn draw_text( + &mut self, + data: Weak>, + rect: Rectangle, + text_scroll: Option, + show_cursor: bool, + ) { + if let Some(cull) = &self.cull + && !cull.intersects(&rect) + { + return; + } + self.commands.push(RenderCommand::DrawText(DrawTextCmd { + rect, + data, + text_scroll, + show_cursor, + })); + } + + #[inline(always)] + pub fn draw_image(&mut self, rect: Rectangle, resource_id: ResourceId) { + if let Some(cull) = &self.cull + && !cull.intersects(&rect) + { + return; + } + self.commands + .push(RenderCommand::DrawImage(DrawImageCmd { rect, resource_id })); + } + + #[inline(always)] + pub fn draw_tiny_vg(&mut self, rect: Rectangle, resource_id: ResourceId, override_color: Option) { + if let Some(cull) = &self.cull + && !cull.intersects(&rect) + { + return; + } + self.commands.push(RenderCommand::DrawTinyVg(DrawTinyVgCmd { + rect, + resource_id, + override_color, + })); + } + + #[inline(always)] + pub fn push_layer(&mut self, rect: Rectangle) { + self.commands.push(RenderCommand::PushLayer(PushLayerCmd::Rect(rect))); + } + + pub fn push_layer_with_bez_path(&mut self, path: BezPath) { + self.commands + .push(RenderCommand::PushLayer(PushLayerCmd::BezPath(path))); + } + + #[inline(always)] + pub fn pop_layer(&mut self) { + self.commands.push(RenderCommand::PopLayer); + } + + pub fn start_overlay(&mut self) { + self.commands.push(RenderCommand::StartOverlay); + self.current_overlay_depth += 1; + } + + pub fn end_overlay(&mut self) { + self.commands.push(RenderCommand::EndOverlay); + self.current_overlay_depth -= 1; + } + + #[inline(always)] + pub fn draw_outset_box_shadow( + &mut self, + box_shadow: BoxShadowCmd, + //rectangle: Rectangle, + ) { + /* if let Some(cull) = &self.cull + && !cull.intersects(&rectangle) + { + return; + }*/ + self.commands.push(RenderCommand::BoxShadowCmd(box_shadow)); + } + + pub fn set_cull(&mut self, cull: Option) { + self.cull = cull; + } +} diff --git a/crates/craft_renderer/src/renderer.rs b/crates/craft_renderer/src/renderer.rs index 7c7b5138..63f56e40 100644 --- a/crates/craft_renderer/src/renderer.rs +++ b/crates/craft_renderer/src/renderer.rs @@ -1,178 +1,14 @@ -use crate::text_renderer_data::TextData; -use craft_primitives::geometry::Rectangle; -use craft_primitives::Color; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; -use peniko::kurbo::Shape; -use peniko::{kurbo, BrushRef, Gradient}; use std::any::Any; -use std::cell::RefCell; -use std::rc::Weak; use std::sync::Arc; -#[derive(Clone)] -pub enum RenderCommand { - DrawRect(Rectangle, Color), - DrawRectOutline(Rectangle, Color, f64), - DrawImage(Rectangle, ResourceIdentifier), - DrawTinyVg(Rectangle, ResourceIdentifier, Option), - DrawText(Weak>, Rectangle, Option, bool), - PushLayer(Rectangle), - PopLayer, - FillBezPath(kurbo::BezPath, Brush), - StartOverlay, - EndOverlay, -} - -#[derive(Clone, Debug)] -pub enum Brush { - Color(Color), - Gradient(Gradient), -} - -impl<'a> From<&'a Brush> for BrushRef<'a> { - fn from(brush: &'a Brush) -> Self { - match brush { - Brush::Color(color) => Self::Solid(*color), - Brush::Gradient(gradient) => Self::Gradient(gradient), - } - } -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct TextScroll { - pub scroll_y: f32, - pub scroll_height: f32, -} - -impl TextScroll { - pub fn new(scroll_y: f32, scroll_height: f32) -> Self { - Self { - scroll_y, - scroll_height, - } - } -} - -#[derive(Debug)] -enum SortedItem { - Overlay(SortedCommands), - Other(u32), -} - -#[derive(Debug)] -pub struct SortedCommands { - children: Vec, -} - -impl SortedCommands { - pub fn draw(render_list: &RenderList, overlay_render: &SortedCommands, on_draw: &mut dyn FnMut(&RenderCommand)) { - let mut others = Vec::new(); - let mut overlays = Vec::new(); - - for child in &overlay_render.children { - match child { - SortedItem::Other(_) => others.push(child), - SortedItem::Overlay(_) => overlays.push(child), - } - } - - for child in others { - if let SortedItem::Other(command_index) = child { - let command = render_list.commands.get(*command_index as usize).unwrap(); - on_draw(command); - } - } - - for child in overlays { - if let SortedItem::Overlay(overlay) = child { - Self::draw(render_list, overlay, on_draw); - } - } - } -} - -pub struct RenderList { - pub targets: Vec<(u64, Rectangle)>, - pub commands: Vec, - /// Stores a sorted list of render command handles. This gets set in `Renderer::sort_render_list`. - pub overlay: SortedCommands, -} - -impl Default for RenderList { - fn default() -> Self { - Self::new() - } -} - -impl RenderList { - pub fn new() -> Self { - Self { - targets: Vec::new(), - commands: Vec::new(), - overlay: SortedCommands { children: vec![] }, - } - } - - pub fn clear(&mut self) { - self.targets.clear(); - self.commands.clear(); - self.overlay.children.clear(); - } - - pub fn draw_rect(&mut self, rectangle: Rectangle, fill_color: Color) { - self.commands.push(RenderCommand::DrawRect(rectangle, fill_color)); - } - - pub fn push_hit_testable(&mut self, id: u64, bounding_box: Rectangle) { - self.targets.push((id, bounding_box)); - } - - pub fn draw_rect_outline(&mut self, rectangle: Rectangle, outline_color: Color, thickness: f64) { - self.commands.push(RenderCommand::DrawRectOutline(rectangle, outline_color, thickness)); - } - - pub fn fill_bez_path(&mut self, path: kurbo::BezPath, brush: Brush) { - self.commands.push(RenderCommand::FillBezPath(path, brush)); - } - - pub fn draw_text( - &mut self, - component: Weak>, - rectangle: Rectangle, - text_scroll: Option, - show_cursor: bool, - ) { - self.commands.push(RenderCommand::DrawText(component, rectangle, text_scroll, show_cursor)); - } - pub fn draw_image(&mut self, rectangle: Rectangle, resource_identifier: ResourceIdentifier) { - self.commands.push(RenderCommand::DrawImage(rectangle, resource_identifier)); - } - - pub fn draw_tiny_vg( - &mut self, - rectangle: Rectangle, - resource_identifier: ResourceIdentifier, - override_color: Option, - ) { - self.commands.push(RenderCommand::DrawTinyVg(rectangle, resource_identifier, override_color)); - } - - pub fn push_layer(&mut self, rect: Rectangle) { - self.commands.push(RenderCommand::PushLayer(rect)); - } - - pub fn pop_layer(&mut self) { - self.commands.push(RenderCommand::PopLayer); - } +use craft_primitives::Color; +use craft_primitives::geometry::Rectangle; - pub fn start_overlay(&mut self) { - self.commands.push(RenderCommand::StartOverlay); - } +use craft_resource_manager::ResourceManager; - pub fn end_overlay(&mut self) { - self.commands.push(RenderCommand::EndOverlay); - } -} +use crate::render_list::RenderList; +pub use crate::screenshot::Screenshot; +use crate::sort_commands::sort_and_cull_render_list_internal; pub trait Renderer: Any { // Surface Functions @@ -182,87 +18,26 @@ pub trait Renderer: Any { fn surface_height(&self) -> f32; fn resize_surface(&mut self, width: f32, height: f32); fn surface_set_clear_color(&mut self, color: Color); - - fn as_any_mut(&mut self) -> &mut dyn Any; - - fn sort_and_cull_render_list(&mut self, render_list: &mut RenderList) { - fn should_cull(rectangle: &Rectangle, window_height: f32) -> bool { - let cull_top = (rectangle.y + rectangle.height) < 0.0; - let cull_bottom = rectangle.y > window_height; - - cull_top || cull_bottom - } - - fn bounding_rect(render_command: &RenderCommand) -> Rectangle { - match render_command { - RenderCommand::DrawRect(rect, _) - | RenderCommand::DrawRectOutline(rect, _, _) - | RenderCommand::DrawImage(rect, _) - | RenderCommand::DrawTinyVg(rect, _, _) - | RenderCommand::DrawText(_, rect, _, _) => *rect, - RenderCommand::FillBezPath(path, _) => Rectangle::from_kurbo(path.bounding_box()), - _ => unreachable!("Cannot compute the bounding rect of this render command."), - } - } - - let window_height = self.surface_height(); - render_list.targets.retain(|(_, bounding_box)| { - !should_cull(bounding_box, window_height) - }); - - let mut current: *mut SortedCommands = &mut render_list.overlay; - let mut stack: Vec<*mut SortedCommands> = vec![current]; - - for (index, command) in render_list.commands.iter().enumerate() { - match &command { - RenderCommand::StartOverlay => { - // Overlay Start - unsafe { - (*current).children.push(SortedItem::Overlay(SortedCommands { children: vec![] })); - match (*current).children.last_mut() { - Some(SortedItem::Overlay(overlay)) => { - stack.push(overlay); - } - _ => { - panic!("OverlayRender stack corrupted"); - } - } - current = *stack.last_mut().unwrap(); - } - } - RenderCommand::EndOverlay => { - // Overlay End - stack.pop(); - current = *stack.last_mut().unwrap(); - } - - // FIXME: If this is a clipping layer, and it is not in bounds we should discard all commands in the clip. - RenderCommand::PushLayer(_) | RenderCommand::PopLayer => { - // Normal Draw Command - unsafe { - (*current).children.push(SortedItem::Other(index as u32)); - } - } + fn as_any_mut(&mut self) -> &mut dyn Any; - _ => { - let bounding_rect = bounding_rect(command); - if !should_cull(&bounding_rect, window_height) { - unsafe { - (*current).children.push(SortedItem::Other(index as u32)); - } - } - } - } - } + fn sort_and_cull_render_list(&mut self, render_list: &mut RenderList) { + sort_and_cull_render_list_internal(self.surface_height(), render_list); } fn prepare_render_list<'a>( &'a mut self, render_list: &'a mut RenderList, resource_manager: Arc, window: Rectangle, - //get_text_renderer: Box Option<&'a TextRender> + 'a>, ); fn submit(&mut self, resource_manager: Arc); + + fn screenshot(&self) -> Screenshot { + Screenshot { + width: 0, + height: 0, + pixels: Vec::new(), + } + } } diff --git a/crates/craft_renderer/src/renderer_type.rs b/crates/craft_renderer/src/renderer_type.rs index ae907a5b..df7cac12 100644 --- a/crates/craft_renderer/src/renderer_type.rs +++ b/crates/craft_renderer/src/renderer_type.rs @@ -1,14 +1,14 @@ use std::fmt::{Display, Formatter}; use std::sync::Arc; + use winit::window::Window; + use crate::blank_renderer::BlankRenderer; use crate::renderer::Renderer; #[cfg(feature = "vello_renderer")] use crate::vello::VelloRenderer; - #[cfg(feature = "vello_cpu_renderer")] use crate::vello_cpu::VelloCpuRenderer; - #[cfg(feature = "vello_hybrid_renderer")] use crate::vello_hybrid::VelloHybridRenderer; @@ -32,10 +32,10 @@ pub enum RendererType { impl Default for RendererType { fn default() -> Self { cfg_if::cfg_if! { - if #[cfg(feature = "vello_renderer")] { - RendererType::Vello - } else if #[cfg(feature = "vello_hybrid_renderer")]{ + if #[cfg(feature = "vello_hybrid_renderer")] { RendererType::VelloHybrid + } else if #[cfg(feature = "vello_renderer")]{ + RendererType::Vello } else if #[cfg(feature = "vello_cpu_renderer")]{ RendererType::VelloCPU } else { @@ -60,7 +60,6 @@ impl Display for RendererType { } impl RendererType { - pub async fn create(&self, window: Arc) -> Box { let renderer: Box = match self { #[cfg(feature = "vello_renderer")] @@ -73,9 +72,9 @@ impl RendererType { // So the linter does not complain about window being unused. let _ = window; Box::new(BlankRenderer) - }, + } }; renderer } -} \ No newline at end of file +} diff --git a/crates/craft_renderer/src/screenshot.rs b/crates/craft_renderer/src/screenshot.rs new file mode 100644 index 00000000..20a58b2c --- /dev/null +++ b/crates/craft_renderer/src/screenshot.rs @@ -0,0 +1,5 @@ +pub struct Screenshot { + pub width: u16, + pub height: u16, + pub pixels: Vec, +} diff --git a/crates/craft_renderer/src/sort_commands.rs b/crates/craft_renderer/src/sort_commands.rs new file mode 100644 index 00000000..6c6ce90d --- /dev/null +++ b/crates/craft_renderer/src/sort_commands.rs @@ -0,0 +1,123 @@ +use crate::{RenderCommand, RenderList}; +use craft_primitives::geometry::{Rectangle, Shape}; + +#[derive(Debug)] +pub enum SortedItem { + Overlay(SortedCommands), + Other(u32), +} + +#[derive(Debug)] +pub struct SortedCommands { + pub children: Vec, +} + +impl SortedCommands { + pub fn draw(render_list: &RenderList, overlay_render: &SortedCommands, on_draw: &mut dyn FnMut(&RenderCommand)) { + let mut others = Vec::new(); + let mut overlays = Vec::new(); + + for child in &overlay_render.children { + match child { + SortedItem::Other(_) => others.push(child), + SortedItem::Overlay(_) => overlays.push(child), + } + } + + for child in others { + if let SortedItem::Other(command_index) = child { + let command = render_list.commands.get(*command_index as usize).unwrap(); + on_draw(command); + } + } + + for child in overlays { + if let SortedItem::Overlay(overlay) = child { + Self::draw(render_list, overlay, on_draw); + } + } + } +} + +pub(crate) fn sort_and_cull_render_list_internal(surface_height: f32, render_list: &mut RenderList) { + fn should_cull(rectangle: &Rectangle, window_height: f32) -> bool { + let cull_top = (rectangle.y + rectangle.height) < 0.0; + let cull_bottom = rectangle.y > window_height; + + cull_top || cull_bottom + } + + fn bounding_rect(render_command: &RenderCommand) -> Rectangle { + match render_command { + RenderCommand::DrawRect(cmd) => cmd.rect, + RenderCommand::DrawRectOutline(cmd) => cmd.rect, + RenderCommand::DrawImage(cmd) => cmd.rect, + RenderCommand::DrawTinyVg(cmd) => cmd.rect, + RenderCommand::DrawText(cmd) => cmd.rect, + RenderCommand::FillBezPath(cmd) => Rectangle::from_kurbo(cmd.path.bounding_box()), + RenderCommand::BoxShadowCmd(cmd) => { + let bounding_box = cmd.path.bounding_box(); + Rectangle::new( + (bounding_box.x0 + cmd.offset.x) as f32, + (bounding_box.y0 + cmd.offset.y) as f32, + (bounding_box.x1 + cmd.offset.x) as f32, + (bounding_box.y1 + cmd.offset.y) as f32, + ) + } + _ => unreachable!("Cannot compute the bounding rect of this render command."), + } + } + + let window_height = surface_height; + + let mut current: *mut SortedCommands = &mut render_list.overlay; + let mut stack: Vec<*mut SortedCommands> = vec![current]; + + for (index, command) in render_list.commands.iter().enumerate() { + match &command { + RenderCommand::StartOverlay => { + // Overlay Start + unsafe { + (*current) + .children + .push(SortedItem::Overlay(SortedCommands { children: vec![] })); + match (*current).children.last_mut() { + Some(SortedItem::Overlay(overlay)) => { + stack.push(overlay); + } + _ => { + panic!("OverlayRender stack corrupted"); + } + } + current = *stack.last_mut().unwrap(); + } + } + RenderCommand::EndOverlay => { + // Overlay End + stack.pop(); + current = *stack.last_mut().unwrap(); + } + + // FIXME: If this is a clipping layer, and it is not in bounds we should discard all commands in the clip. + RenderCommand::PushLayer(_) | RenderCommand::PopLayer => { + // Normal Draw Command + unsafe { + (*current).children.push(SortedItem::Other(index as u32)); + } + } + + RenderCommand::SetTransform(_) => unsafe { + (*current).children.push(SortedItem::Other(index as u32)); + }, + + _ => { + let bounding_rect = bounding_rect(command); + if !should_cull(&bounding_rect, window_height) { + unsafe { + (*current).children.push(SortedItem::Other(index as u32)); + } + } + } + } + } +} diff --git a/crates/craft_renderer/src/target_item.rs b/crates/craft_renderer/src/target_item.rs new file mode 100644 index 00000000..2431fbc1 --- /dev/null +++ b/crates/craft_renderer/src/target_item.rs @@ -0,0 +1,23 @@ +use craft_primitives::geometry::Rectangle; + +#[derive(Debug)] +pub struct TargetItem { + pub custom_id: u64, + pub rectangle: Rectangle, + pub overlay_depth: u64, +} + +impl TargetItem { + pub fn new(custom_id: u64, rectangle: Rectangle, overlay_depth: u64) -> Self { + Self { + custom_id, + rectangle, + overlay_depth, + } + } + + // Sorts the items by the overlay depth and in ascending order. + pub fn sort_items_by_overlay_depth(targets: &mut [TargetItem]) { + targets.sort_by_key(|t1| t1.overlay_depth); + } +} diff --git a/crates/craft_renderer/src/text_renderer_data.rs b/crates/craft_renderer/src/text_renderer_data.rs index fd944585..42eaee1a 100644 --- a/crates/craft_renderer/src/text_renderer_data.rs +++ b/crates/craft_renderer/src/text_renderer_data.rs @@ -1,7 +1,22 @@ +use craft_primitives::ColorBrush; use craft_primitives::geometry::Rectangle; use peniko::Color; use peniko::kurbo::{Affine, Line}; -use craft_primitives::ColorBrush; + +#[derive(Debug, Clone, Copy, Default)] +pub struct TextScroll { + pub scroll_y: f32, + pub scroll_height: f32, +} + +impl TextScroll { + pub fn new(scroll_y: f32, scroll_height: f32) -> Self { + Self { + scroll_y, + scroll_height, + } + } +} #[derive(Clone, Debug)] pub struct TextRender { @@ -49,5 +64,4 @@ pub struct TextRenderGlyph { pub trait TextData { fn get_text_renderer(&self) -> Option<&TextRender>; - -} \ No newline at end of file +} diff --git a/crates/craft_renderer/src/tinyvg_helpers.rs b/crates/craft_renderer/src/tinyvg_helpers.rs index fc37758a..cfd83e7f 100644 --- a/crates/craft_renderer/src/tinyvg_helpers.rs +++ b/crates/craft_renderer/src/tinyvg_helpers.rs @@ -1,11 +1,11 @@ -use crate::renderer::Brush; use peniko::color::AlphaColor; -use peniko::kurbo::BezPath; -use peniko::kurbo::SvgArc; -use peniko::{kurbo, Color, Gradient}; +use peniko::kurbo::{BezPath, SvgArc}; +use peniko::{Color, Gradient, kurbo}; use tinyvg_rs::color_table::ColorTable; use tinyvg_rs::commands::{Path, PathCommand, Point, Style}; +use crate::Brush; + #[allow(clippy::wrong_self_convention)] /// Convert the TinyVG point to a kurbo color. pub(crate) fn to_kurbo_point(point: Point) -> kurbo::Point { diff --git a/crates/craft_renderer/src/vello/mod.rs b/crates/craft_renderer/src/vello/mod.rs index 918fe0da..170682f2 100644 --- a/crates/craft_renderer/src/vello/mod.rs +++ b/crates/craft_renderer/src/vello/mod.rs @@ -1,27 +1,33 @@ mod tinyvg; -use crate::image_adapter::ImageAdapter; -use crate::renderer::{RenderCommand, RenderList, Renderer, SortedCommands, TextScroll}; -use crate::text_renderer_data::TextRenderLine; -use crate::vello::tinyvg::draw_tiny_vg; -use craft_primitives::geometry::Rectangle; +use std::any::Any; +use std::sync::Arc; + use craft_primitives::Color; -use craft_resource_manager::resource::Resource; +use craft_primitives::geometry::Rectangle; use craft_resource_manager::ResourceManager; +use craft_resource_manager::resource::Resource; + use peniko::{BrushRef, ImageAlphaType}; -use std::any::Any; -use std::sync::Arc; + use vello::kurbo::{Affine, Rect, Stroke}; use vello::peniko::{BlendMode, Blob, Fill}; -use vello::{kurbo, peniko, AaConfig, Error, RendererOptions}; -use vello::{Glyph, Scene}; +use vello::{AaConfig, Error, Glyph, RendererOptions, Scene, kurbo, peniko}; + use wgpu::util::TextureBlitter; -use wgpu::{ - Adapter, Device, Instance, Limits, MemoryHints, Queue, Surface, SurfaceConfiguration, SurfaceError, SurfaceTexture, - Texture, TextureFormat, TextureView, -}; +use wgpu::{Adapter, Device, Instance, Limits, MemoryHints, Queue, Surface, SurfaceConfiguration, SurfaceError, SurfaceTexture, Texture, TextureFormat, TextureView}; + use winit::window::Window; +use crate::RenderCommand; +use crate::image_adapter::ImageAdapter; +use crate::render_command::PushLayerCmd; +use crate::render_list::RenderList; +use crate::renderer::Renderer; +use crate::sort_commands::SortedCommands; +use crate::text_renderer_data::{TextRenderLine, TextScroll}; +use crate::vello::tinyvg::draw_tiny_vg; + pub struct RenderSurface { pub surface: Surface<'static>, pub surface_config: SurfaceConfiguration, @@ -29,6 +35,27 @@ pub struct RenderSurface { pub surface_view: wgpu::TextureView, } +pub struct VelloRenderer { + pub device: Device, + #[allow(dead_code)] + pub adapter: Adapter, + pub queue: Queue, + #[allow(dead_code)] + pub instance: Instance, + pub render_surface: RenderSurface, + pub texture_blitter: TextureBlitter, + pub renderer: vello::Renderer, + + // A vello Scene which is a data structure which allows one to build up a + // description a scene to be drawn (with paths, fills, images, text, etc) + // which is then passed to a renderer for rendering + scene: Scene, + pub surface_clear_color: Color, + pub render_into_texture: bool, + + transform: Affine, +} + impl RenderSurface { pub fn create_surface_textures(device: &Device, surface_width: u32, surface_height: u32) -> (Texture, TextureView) { let surface_texture = device.create_texture(&wgpu::TextureDescriptor { @@ -69,7 +96,9 @@ impl RenderSurface { panic!("Failed to acquire surface texture: {err:?}"); } } - self.surface.get_current_texture().expect("Failed to get surface texture after resize") + self.surface + .get_current_texture() + .expect("Failed to get surface texture after resize") } } } @@ -132,25 +161,6 @@ impl RenderSurface { } } -pub struct VelloRenderer { - pub device: Device, - #[allow(dead_code)] - pub adapter: Adapter, - pub queue: Queue, - #[allow(dead_code)] - pub instance: Instance, - pub render_surface: RenderSurface, - pub texture_blitter: TextureBlitter, - pub renderer: vello::Renderer, - - // A vello Scene which is a data structure which allows one to build up a - // description a scene to be drawn (with paths, fills, images, text, etc) - // which is then passed to a renderer for rendering - scene: Scene, - pub surface_clear_color: Color, - pub render_into_texture: bool, -} - fn create_vello_renderer(device: &Device) -> vello::Renderer { vello::Renderer::new( device, @@ -202,6 +212,7 @@ async fn new_device(instance: &Instance, surface: &Surface<'_>) -> (Device, Queu label: None, required_features: features & maybe_features, required_limits: limits, + experimental_features: Default::default(), memory_hints: MemoryHints::default(), trace: Default::default(), }) @@ -231,18 +242,19 @@ impl VelloRenderer { scene: Scene::new(), surface_clear_color: Color::WHITE, render_into_texture, + transform: Default::default(), } } } -fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color) { +fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color, transform: &Affine) { let rect = Rect::new( rectangle.x as f64, rectangle.y as f64, (rectangle.x + rectangle.width) as f64, (rectangle.y + rectangle.height) as f64, ); - scene.fill(Fill::NonZero, Affine::IDENTITY, fill_color, None, &rect); + scene.fill(Fill::NonZero, *transform, fill_color, None, &rect); } impl Renderer for VelloRenderer { @@ -272,18 +284,29 @@ impl Renderer for VelloRenderer { resource_manager: Arc, window: Rectangle, ) { + self.transform = Affine::IDENTITY; + SortedCommands::draw(render_list, &render_list.overlay, &mut |command: &RenderCommand| { let scene = &mut self.scene; match command { - RenderCommand::DrawRect(rectangle, fill_color) => { - vello_draw_rect(scene, *rectangle, *fill_color); + RenderCommand::SetTransform(cmd) => { + self.transform = cmd.transform; } - RenderCommand::DrawRectOutline(rectangle, outline_color, thickness) => { - self.scene.stroke(&Stroke::new(*thickness), Affine::IDENTITY, outline_color, None, &rectangle.to_kurbo()); + RenderCommand::DrawRect(cmd) => { + vello_draw_rect(scene, cmd.rect, cmd.color, &self.transform); } - RenderCommand::DrawImage(rectangle, resource_identifier) => { - let resource = resource_manager.get(resource_identifier); + RenderCommand::DrawRectOutline(cmd) => { + self.scene.stroke( + &Stroke::new(cmd.thickness), + Affine::IDENTITY, + cmd.outline_color, + None, + &cmd.rect.to_kurbo(), + ); + } + RenderCommand::DrawImage(cmd) => { + let resource = resource_manager.get(&cmd.resource_id); if let Some(resource) = resource && let Resource::Image(resource) = resource.as_ref() { @@ -297,26 +320,27 @@ impl Renderer for VelloRenderer { width: image.width(), height: image.height(), }; - let vello_image = vello::peniko::ImageBrush::new(vello_image); - let mut transform = Affine::IDENTITY; - transform = - transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - transform = transform.pre_scale_non_uniform( - rectangle.width as f64 / image.width() as f64, - rectangle.height as f64 / image.height() as f64, + let mut image_transform = Affine::IDENTITY; + image_transform = + image_transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + image_transform = image_transform.pre_scale_non_uniform( + cmd.rect.width as f64 / image.width() as f64, + cmd.rect.height as f64 / image.height() as f64, ); - scene.draw_image(&vello_image, transform); + image_transform = self.transform * image_transform; + scene.draw_image(&vello_image, image_transform); } } - RenderCommand::DrawText(text_render, rect, text_scroll, show_cursor) => { + RenderCommand::DrawText(cmd) => { let text_transform = - Affine::default().with_translation(kurbo::Vec2::new(rect.x as f64, rect.y as f64)); - let scroll = text_scroll.unwrap_or(TextScroll::default()).scroll_y; - let text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); + Affine::default().with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + let scroll = cmd.text_scroll.unwrap_or(TextScroll::default()).scroll_y; + let mut text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); + text_transform = self.transform * text_transform; - let c = text_render.upgrade(); + let c = cmd.data.upgrade(); if c.is_none() { return; } @@ -339,7 +363,7 @@ impl Renderer for VelloRenderer { for item in &line.items { if let Some(first_glyph) = item.glyphs.first() { // Cull the glyphs vertically that are outside the window - let gy = first_glyph.y + rect.y - scroll; + let gy = first_glyph.y + cmd.rect.y - scroll; if gy < window.y { skip_line = true; break; @@ -357,22 +381,22 @@ impl Renderer for VelloRenderer { cull_and_process(&mut |line: &TextRenderLine| { for (background, color) in &line.backgrounds { let background_rect = Rectangle { - x: background.x + rect.x, - y: -scroll + background.y + rect.y, + x: background.x + cmd.rect.x, + y: -scroll + background.y + cmd.rect.y, width: background.width, height: background.height, }; - vello_draw_rect(scene, background_rect, *color); + vello_draw_rect(scene, background_rect, *color, &self.transform); } for (selection, selection_color) in &line.selections { let selection_rect = Rectangle { - x: selection.x + rect.x, - y: -scroll + selection.y + rect.y, + x: selection.x + cmd.rect.x, + y: -scroll + selection.y + cmd.rect.y, width: selection.width, height: selection.height, }; - vello_draw_rect(scene, selection_rect, *selection_color); + vello_draw_rect(scene, selection_rect, *selection_color, &self.transform); } }); @@ -392,7 +416,10 @@ impl Renderer for VelloRenderer { .draw_glyphs(&item.font) .font_size(item.font_size) .brush(BrushRef::Solid( - text_render.override_brush.map(|b| b.color).unwrap_or_else(|| item.brush.color), + text_render + .override_brush + .map(|b| b.color) + .unwrap_or_else(|| item.brush.color), )) .transform(text_transform) .glyph_transform(item.glyph_transform) @@ -407,39 +434,49 @@ impl Renderer for VelloRenderer { } }); - if *show_cursor && let Some((cursor, cursor_color)) = &text_render.cursor { + if cmd.show_cursor + && let Some((cursor, cursor_color)) = &text_render.cursor + { let cursor_rect = Rectangle { - x: cursor.x + rect.x, - y: -scroll + cursor.y + rect.y, + x: cursor.x + cmd.rect.x, + y: -scroll + cursor.y + cmd.rect.y, width: cursor.width, height: cursor.height, }; - vello_draw_rect(scene, cursor_rect, *cursor_color); + vello_draw_rect(scene, cursor_rect, *cursor_color, &self.transform); } } - RenderCommand::DrawTinyVg(rectangle, resource_identifier, override_color) => { + RenderCommand::DrawTinyVg(cmd) => { draw_tiny_vg( scene, - *rectangle, + cmd.rect, resource_manager.clone(), - resource_identifier.clone(), - override_color, + cmd.resource_id.clone(), + &cmd.override_color, + &self.transform, ); } - RenderCommand::PushLayer(rect) => { - let clip = Rect::new( - rect.x as f64, - rect.y as f64, - (rect.x + rect.width) as f64, - (rect.y + rect.height) as f64, - ); - scene.push_layer(BlendMode::default(), 1.0, Affine::IDENTITY, &clip); + RenderCommand::PushLayer(cmd) => { + match cmd { + PushLayerCmd::BezPath(p) => { + scene.push_layer(Fill::NonZero, BlendMode::default(), 1.0, Affine::IDENTITY, p); + } + PushLayerCmd::Rect(r) => { + scene.push_layer( + Fill::NonZero, + BlendMode::default(), + 1.0, + Affine::IDENTITY, + &r.to_kurbo(), + ); + } + }; } RenderCommand::PopLayer => { scene.pop_layer(); } - RenderCommand::FillBezPath(path, brush) => { - scene.fill(Fill::NonZero, Affine::IDENTITY, brush, None, &path); + RenderCommand::FillBezPath(cmd) => { + scene.fill(Fill::NonZero, self.transform, &cmd.brush, None, &cmd.path); } _ => {} } @@ -471,9 +508,11 @@ impl Renderer for VelloRenderer { if !self.render_into_texture { let swapchain_surface_texture = - self.render_surface.get_swapchain_surface_texture(&self.device, width, height); - let swapchain_surface_texture_view = - swapchain_surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); + self.render_surface + .get_swapchain_surface_texture(&self.device, width, height); + let swapchain_surface_texture_view = swapchain_surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Surface Blit"), }); diff --git a/crates/craft_renderer/src/vello/tinyvg.rs b/crates/craft_renderer/src/vello/tinyvg.rs index e8f65ff7..9c6f318d 100644 --- a/crates/craft_renderer/src/vello/tinyvg.rs +++ b/crates/craft_renderer/src/vello/tinyvg.rs @@ -1,15 +1,17 @@ -use crate::tinyvg_helpers; +use std::sync::Arc; + use craft_primitives::geometry::Rectangle; use craft_resource_manager::resource::Resource; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; +use craft_resource_manager::{ResourceId, ResourceManager}; use peniko::kurbo::{Affine, Line, Stroke}; -use peniko::{kurbo, Color, Fill}; -use std::sync::Arc; +use peniko::{Color, Fill, kurbo}; use tinyvg_rs::color_table::ColorTable; use tinyvg_rs::commands::{DrawCommand, Path, PathCommand, Segment, Style}; use tinyvg_rs::common::Unit; use vello::Scene; +use crate::tinyvg_helpers; + pub(crate) fn draw_path( scene: &mut Scene, path: &Path, @@ -32,10 +34,11 @@ pub(crate) fn draw_tiny_vg( scene: &mut Scene, rectangle: Rectangle, resource_manager: Arc, - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, override_color: &Option, + transform: &Affine, ) { - let resource = resource_manager.get(&resource_identifier); + let resource = resource_manager.get(&resource_id); if let Some(resource) = resource && let Resource::TinyVg(resource) = resource.as_ref() { @@ -44,7 +47,7 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let mut vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -56,12 +59,14 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + vg_transform = *transform * vg_transform; + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -77,18 +82,34 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &path, + &data.style, + None, + &tiny_vg.color_table, + &vg_transform, + override_color, + ); } DrawCommand::FillRectangles(data) => { let brush = tinyvg_helpers::get_brush(&data.style, &tiny_vg.color_table, override_color); for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - scene.fill(Fill::EvenOdd, affine, &brush, None, &rectangle); + scene.fill(Fill::EvenOdd, vg_transform, &brush, None, &rectangle); } } DrawCommand::FillPath(data) => { - draw_path(scene, &data.path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.style, + None, + &tiny_vg.color_table, + &vg_transform, + override_color, + ); } DrawCommand::DrawLines(data) => { let brush = tinyvg_helpers::get_brush(&data.line_style, &tiny_vg.color_table, override_color); @@ -98,7 +119,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); } } DrawCommand::DrawLineLoop(data) => { @@ -106,9 +127,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); start = *point; } } @@ -117,9 +140,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); start = *point; } } @@ -130,7 +155,7 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -147,14 +172,22 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &path, + &data.fill_style, + None, + &tiny_vg.color_table, + &vg_transform, + override_color, + ); draw_path( scene, &path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -164,19 +197,33 @@ pub(crate) fn draw_tiny_vg( for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - scene.fill(Fill::EvenOdd, affine, &fill_brush, None, &rectangle); - scene.stroke(&Stroke::new(data.line_width.0), affine, &line_brush, None, &rectangle); + scene.fill(Fill::EvenOdd, vg_transform, &fill_brush, None, &rectangle); + scene.stroke( + &Stroke::new(data.line_width.0), + vg_transform, + &line_brush, + None, + &rectangle, + ); } } DrawCommand::OutlineFillPath(data) => { - draw_path(scene, &data.path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.fill_style, + None, + &tiny_vg.color_table, + &vg_transform, + override_color, + ); draw_path( scene, &data.path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } diff --git a/crates/craft_renderer/src/vello_cpu/mod.rs b/crates/craft_renderer/src/vello_cpu/mod.rs index 3befd9ef..e5e732c1 100644 --- a/crates/craft_renderer/src/vello_cpu/mod.rs +++ b/crates/craft_renderer/src/vello_cpu/mod.rs @@ -1,29 +1,47 @@ pub(crate) mod tinyvg; -use crate::image_adapter::ImageAdapter; -use crate::renderer::{RenderList, Renderer, SortedCommands, TextScroll}; -use crate::text_renderer_data::TextRenderLine; -use crate::vello_cpu::tinyvg::draw_tiny_vg; -use crate::{Brush, RenderCommand}; +use std::any::Any; +use std::num::{NonZero, NonZeroU32}; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + use craft_primitives::geometry::Rectangle; -use craft_resource_manager::resource::Resource; use craft_resource_manager::ResourceManager; -use peniko::kurbo::Affine; -use peniko::kurbo::Shape; -use peniko::{kurbo, Blob, Color, Fill, ImageAlphaType}; +use craft_resource_manager::resource::Resource; + +use peniko::kurbo::{Affine, Shape}; +use peniko::{BlendMode, Blob, Color, Compose, Fill, ImageAlphaType, Mix, kurbo}; + use softbuffer::Buffer; -use std::any::Any; -use std::num::NonZero; -use std::num::NonZeroU32; -use std::ops::Deref; -use std::ops::DerefMut; -use std::sync::Arc; + +use vello_common::filter_effects::{Filter, FilterFunction}; use vello_common::glyph::Glyph; use vello_common::kurbo::Stroke; use vello_common::paint::PaintType; use vello_cpu::{Pixmap, RenderContext}; + use winit::window::Window; +use crate::RenderCommand; +use crate::helpers::{brush_to_paint, rgba_to_encoded_u32}; +use crate::image_adapter::ImageAdapter; +use crate::render_command::{BoxShadowCmd, PushLayerCmd}; +use crate::render_list::RenderList; +use crate::renderer::Renderer; +use crate::screenshot::Screenshot; +use crate::sort_commands::SortedCommands; +use crate::text_renderer_data::{TextRenderLine, TextScroll}; +use crate::vello_cpu::tinyvg::draw_tiny_vg; + +pub(crate) struct VelloCpuRenderer { + render_context: RenderContext, + pixmap: Pixmap, + surface: Surface, + clear_color: Color, + window_width: u16, + window_height: u16, +} + pub struct Surface { inner_surface: softbuffer::Surface, Arc>, } @@ -62,15 +80,6 @@ fn vello_draw_rect(scene: &mut RenderContext, rectangle: Rectangle, fill_color: scene.fill_rect(&rectangle.to_kurbo()); } -pub(crate) struct VelloCpuRenderer { - render_context: RenderContext, - pixmap: Pixmap, - surface: Surface, - clear_color: Color, - window_width: u16, - window_height: u16, -} - impl VelloCpuRenderer { pub fn new(window: Arc) -> Self { let width = window.inner_size().width as u16; @@ -114,7 +123,10 @@ impl Renderer for VelloCpuRenderer { self.window_width = width as u16; self.window_height = height as u16; self.surface - .resize(NonZeroU32::new(width as u32).unwrap(), NonZeroU32::new(height as u32).unwrap()) + .resize( + NonZeroU32::new(width as u32).unwrap(), + NonZeroU32::new(height as u32).unwrap(), + ) .expect("TODO: panic message"); self.pixmap = Pixmap::new(width as u16, height as u16); self.render_context = RenderContext::new(width as u16, height as u16); @@ -133,7 +145,6 @@ impl Renderer for VelloCpuRenderer { render_list: &'a mut RenderList, resource_manager: Arc, window: Rectangle, - //get_text_renderer: Box Option<&'a TextRender> + 'a>, ) { vello_draw_rect( &mut self.render_context, @@ -148,17 +159,20 @@ impl Renderer for VelloCpuRenderer { SortedCommands::draw(render_list, &render_list.overlay, &mut |command: &RenderCommand| { match command { - RenderCommand::DrawRect(rectangle, fill_color) => { - self.render_context.set_paint(PaintType::Solid(*fill_color)); - self.render_context.fill_rect(&rectangle.to_kurbo()); + RenderCommand::SetTransform(cmd) => { + self.render_context.set_transform(cmd.transform); } - RenderCommand::DrawRectOutline(rectangle, outline_color) => { - self.render_context.set_stroke(Stroke::new(1.0)); - self.render_context.set_paint(PaintType::Solid(*outline_color)); - self.render_context.stroke_rect(&rectangle.to_kurbo()); + RenderCommand::DrawRect(cmd) => { + self.render_context.set_paint(PaintType::Solid(cmd.color)); + self.render_context.fill_rect(&cmd.rect.to_kurbo()); } - RenderCommand::DrawImage(rectangle, resource_identifier) => { - let resource = resource_manager.get(resource_identifier); + RenderCommand::DrawRectOutline(cmd) => { + self.render_context.set_stroke(Stroke::new(cmd.thickness)); + self.render_context.set_paint(PaintType::Solid(cmd.outline_color)); + self.render_context.stroke_rect(&cmd.rect.to_kurbo()); + } + RenderCommand::DrawImage(cmd) => { + let resource = resource_manager.get(&cmd.resource_id); if let Some(resource) = resource && let Resource::Image(resource) = resource.as_ref() @@ -174,14 +188,16 @@ impl Renderer for VelloCpuRenderer { height: image.height(), }; - let mut transform = Affine::IDENTITY; - transform = - transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - transform = transform.pre_scale_non_uniform( - rectangle.width as f64 / image.width() as f64, - rectangle.height as f64 / image.height() as f64, + let scene_state = self.render_context.save_current_state(); + let mut image_transform = Affine::IDENTITY; + image_transform = + image_transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + image_transform = image_transform.pre_scale_non_uniform( + cmd.rect.width as f64 / image.width() as f64, + cmd.rect.height as f64 / image.height() as f64, ); - self.render_context.set_transform(transform); + self.render_context + .set_transform(scene_state.transform * image_transform); let is = vello_common::paint::ImageSource::from_peniko_image_data(&id); @@ -198,16 +214,16 @@ impl Renderer for VelloCpuRenderer { image.width() as f64, image.height() as f64, )); - self.render_context.reset_transform(); + self.render_context.restore_state(scene_state); } } - RenderCommand::DrawText(text_render, rect, text_scroll, show_cursor) => { - let text_transform = - kurbo::Affine::default().with_translation(kurbo::Vec2::new(rect.x as f64, rect.y as f64)); - let scroll = text_scroll.unwrap_or(TextScroll::default()).scroll_y; + RenderCommand::DrawText(cmd) => { + let text_transform = kurbo::Affine::default() + .with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + let scroll = cmd.text_scroll.unwrap_or(TextScroll::default()).scroll_y; let text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); - let c = text_render.upgrade(); + let c = cmd.data.upgrade(); if c.is_none() { return; } @@ -230,7 +246,7 @@ impl Renderer for VelloCpuRenderer { for item in &line.items { if let Some(first_glyph) = item.glyphs.first() { // Cull the glyphs vertically that are outside the window - let gy = first_glyph.y + rect.y - scroll; + let gy = first_glyph.y + cmd.rect.y - scroll; if gy < window.y { skip_line = true; break; @@ -248,8 +264,8 @@ impl Renderer for VelloCpuRenderer { cull_and_process(&mut |line: &TextRenderLine| { for (background, color) in &line.backgrounds { let background_rect = Rectangle { - x: background.x + rect.x, - y: -scroll + background.y + rect.y, + x: background.x + cmd.rect.x, + y: -scroll + background.y + cmd.rect.y, width: background.width, height: background.height, }; @@ -258,8 +274,8 @@ impl Renderer for VelloCpuRenderer { for (selection, selection_color) in &line.selections { let selection_rect = Rectangle { - x: selection.x + rect.x, - y: -scroll + selection.y + rect.y, + x: selection.x + cmd.rect.x, + y: -scroll + selection.y + cmd.rect.y, width: selection.width, height: selection.height, }; @@ -267,25 +283,25 @@ impl Renderer for VelloCpuRenderer { } }); + let scene_state = self.render_context.save_current_state(); + self.render_context + .set_transform(scene_state.transform * text_transform); cull_and_process(&mut |line: &TextRenderLine| { for item in &line.items { if let Some(underline) = &item.underline { - self.render_context.set_transform(text_transform); self.render_context.set_stroke(Stroke::new(underline.width.into())); self.render_context.set_paint(PaintType::from(underline.brush.color)); self.render_context.stroke_path(&underline.line.to_path(0.1)); } self.render_context.set_paint(PaintType::from( - text_render.override_brush.map(|b| b.color).unwrap_or_else(|| item.brush.color), + text_render + .override_brush + .map(|b| b.color) + .unwrap_or_else(|| item.brush.color), )); - self.render_context.reset_transform(); - let glyph_run_builder = self - .render_context - .glyph_run(&item.font) - .font_size(item.font_size) - .glyph_transform(text_transform); + let glyph_run_builder = self.render_context.glyph_run(&item.font).font_size(item.font_size); glyph_run_builder.fill_glyphs(item.glyphs.iter().map(|glyph| Glyph { id: glyph.id, x: glyph.x, @@ -293,44 +309,47 @@ impl Renderer for VelloCpuRenderer { })); } }); + self.render_context.restore_state(scene_state); - if *show_cursor && let Some((cursor, cursor_color)) = &text_render.cursor { + if cmd.show_cursor + && let Some((cursor, cursor_color)) = &text_render.cursor + { let cursor_rect = Rectangle { - x: cursor.x + rect.x, - y: -scroll + cursor.y + rect.y, + x: cursor.x + cmd.rect.x, + y: -scroll + cursor.y + cmd.rect.y, width: cursor.width, height: cursor.height, }; vello_draw_rect(&mut self.render_context, cursor_rect, *cursor_color); } } - RenderCommand::PushLayer(rect) => { - let clip_path = Some( - peniko::kurbo::Rect::from_origin_size( - peniko::kurbo::Point::new(rect.x as f64, rect.y as f64), - peniko::kurbo::Size::new(rect.width as f64, rect.height as f64), - ) - .into_path(0.1), - ); - self.render_context.push_layer(clip_path.as_ref(), None, None, None); + RenderCommand::PushLayer(cmd) => { + let clip_path = match cmd { + PushLayerCmd::BezPath(path) => path, + PushLayerCmd::Rect(rect) => &rect.to_kurbo().into_path(0.1), + }; + + self.render_context.push_layer(Some(clip_path), None, None, None, None); } RenderCommand::PopLayer => { self.render_context.pop_layer(); } - RenderCommand::FillBezPath(path, brush) => { - self.render_context.set_paint(brush_to_paint(brush)); - self.render_context.fill_path(path); + RenderCommand::FillBezPath(cmd) => { + self.render_context.set_paint(brush_to_paint(&cmd.brush)); + self.render_context.fill_path(&cmd.path); } - RenderCommand::DrawTinyVg(rectangle, resource_identifier, override_color) => { + RenderCommand::DrawTinyVg(cmd) => { draw_tiny_vg( &mut self.render_context, - *rectangle, + cmd.rect, &resource_manager, - resource_identifier.clone(), - override_color, + cmd.resource_id.clone(), + &cmd.override_color, ); } - _ => {} + RenderCommand::StartOverlay => {} + RenderCommand::EndOverlay => {} + RenderCommand::BoxShadowCmd(cmd) => self.draw_box_shadow(cmd), } }); } @@ -342,6 +361,14 @@ impl Renderer for VelloCpuRenderer { buffer.present().expect("Failed to present buffer"); self.render_context.reset(); } + + fn screenshot(&self) -> Screenshot { + Screenshot { + width: self.pixmap.width(), + height: self.pixmap.height(), + pixels: self.pixmap.data_as_u8_slice().to_vec(), + } + } } impl VelloCpuRenderer { @@ -361,15 +388,54 @@ impl VelloCpuRenderer { buffer } -} -fn brush_to_paint(brush: &Brush) -> PaintType { - match brush { - Brush::Color(color) => PaintType::Solid(*color), - Brush::Gradient(gradient) => PaintType::Gradient(gradient.clone()), + pub fn draw_box_shadow(&mut self, box_shadow: &BoxShadowCmd) { + let scene_state = self.render_context.save_current_state(); + let radius = box_shadow.blur_radius / 2.0; + let filter = Some(Filter::from_function(FilterFunction::Blur { + radius: box_shadow.blur_radius as f32, + })); + + if box_shadow.inset { + let mut clip_path = kurbo::BezPath::new(); + let outline_rect = box_shadow.border_box.expand((radius * 3.0) as f32).to_kurbo(); + clip_path.extend(&outline_rect.to_path(0.1)); + clip_path.extend(&box_shadow.path); + self.render_context + .push_layer(Some(&box_shadow.outline), None, None, None, filter); + self.render_context.set_fill_rule(Fill::EvenOdd); + self.render_context.set_paint(box_shadow.color); + self.render_context.fill_path(&clip_path); + self.render_context.pop_layer(); + self.render_context.set_fill_rule(Fill::NonZero); + } else { + self.render_context.push_layer( + None, + Some(BlendMode::new(Mix::Normal, Compose::SrcOver)), + None, + None, + filter, + ); + + self.render_context + .set_transform(scene_state.transform * Affine::translate(box_shadow.offset)); + + self.render_context.set_paint(box_shadow.color); + self.render_context.fill_path(&box_shadow.path); + + self.render_context.set_transform(scene_state.transform); + + self.render_context + .set_blend_mode(BlendMode::new(Mix::Normal, Compose::DestOut)); + self.render_context.set_paint(Color::WHITE); + self.render_context.fill_path(&box_shadow.outline); + + self.render_context + .set_blend_mode(BlendMode::new(Mix::Normal, Compose::SrcOver)); + + self.render_context.pop_layer(); + + self.render_context.restore_state(scene_state); + } } } - -const fn rgba_to_encoded_u32(r: u32, g: u32, b: u32, a: u32) -> u32 { - b | (g << 8) | (r << 16) | (a << 24) -} diff --git a/crates/craft_renderer/src/vello_cpu/tinyvg.rs b/crates/craft_renderer/src/vello_cpu/tinyvg.rs index e527b675..45962e47 100644 --- a/crates/craft_renderer/src/vello_cpu/tinyvg.rs +++ b/crates/craft_renderer/src/vello_cpu/tinyvg.rs @@ -1,26 +1,25 @@ +use std::sync::Arc; + use craft_primitives::geometry::Rectangle; -use crate::vello_cpu::brush_to_paint; -use crate::{tinyvg_helpers, Brush}; use craft_resource_manager::resource::Resource; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; +use craft_resource_manager::{ResourceId, ResourceManager}; use peniko::kurbo::{Affine, BezPath, Line, Shape, Stroke}; -use peniko::Color; -use peniko::{kurbo, Fill}; -use std::sync::Arc; +use peniko::{Color, Fill, kurbo}; use tinyvg_rs::color_table::ColorTable; use tinyvg_rs::commands::{DrawCommand, Path, PathCommand, Segment, Style}; use tinyvg_rs::common::Unit; use vello_cpu::RenderContext; -fn stroke_path(scene: &mut RenderContext, bez_path: &BezPath, affine: &Affine, line_width: f64, brush: &Brush) { +use crate::helpers::brush_to_paint; +use crate::{Brush, tinyvg_helpers}; + +fn stroke_path(scene: &mut RenderContext, bez_path: &BezPath, line_width: f64, brush: &Brush) { scene.set_stroke(Stroke::new(line_width)); - scene.set_transform(*affine); scene.set_paint(brush_to_paint(brush)); scene.stroke_path(bez_path); } -fn fill_path(scene: &mut RenderContext, bez_path: &BezPath, affine: &Affine, brush: &Brush) { - scene.set_transform(*affine); +fn fill_path(scene: &mut RenderContext, bez_path: &BezPath, brush: &Brush) { scene.set_paint(brush_to_paint(brush)); scene.set_fill_rule(Fill::EvenOdd); scene.fill_path(bez_path); @@ -32,15 +31,14 @@ pub(crate) fn draw_path( fill_style: &Style, line_width: Option<&Unit>, color_table: &ColorTable, - affine: &Affine, override_color: &Option, ) { let (bezier_path, brush) = tinyvg_helpers::assemble_path(path, fill_style, color_table, override_color); if let Some(line_width) = line_width { - stroke_path(scene, &bezier_path, affine, line_width.0, &brush); + stroke_path(scene, &bezier_path, line_width.0, &brush); } else { - fill_path(scene, &bezier_path, affine, &brush); + fill_path(scene, &bezier_path, &brush); } } @@ -48,10 +46,10 @@ pub(crate) fn draw_tiny_vg( scene: &mut RenderContext, rectangle: Rectangle, resource_manager: &Arc, - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, override_color: &Option, ) { - let resource = resource_manager.get(&resource_identifier); + let resource = resource_manager.get(&resource_id); if resource.is_none() { return; } @@ -63,7 +61,7 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -75,12 +73,15 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + let vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + let vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + let scene_state = scene.save_current_state(); + scene.set_transform(scene_state.transform * vg_transform); + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -96,18 +97,25 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path(scene, &path, &data.style, None, &tiny_vg.color_table, override_color); } DrawCommand::FillRectangles(data) => { let brush = tinyvg_helpers::get_brush(&data.style, &tiny_vg.color_table, override_color); for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - fill_path(scene, &rectangle.into_path(0.1), &affine, &brush); + fill_path(scene, &rectangle.into_path(0.1), &brush); } } DrawCommand::FillPath(data) => { - draw_path(scene, &data.path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.style, + None, + &tiny_vg.color_table, + override_color, + ); } DrawCommand::DrawLines(data) => { let brush = tinyvg_helpers::get_brush(&data.line_style, &tiny_vg.color_table, override_color); @@ -117,7 +125,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); } } DrawCommand::DrawLineLoop(data) => { @@ -125,9 +133,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -136,9 +146,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -149,7 +161,6 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -166,14 +177,20 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &path, + &data.fill_style, + None, + &tiny_vg.color_table, + override_color, + ); draw_path( scene, &path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -184,19 +201,25 @@ pub(crate) fn draw_tiny_vg( let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); let rec_bez_path = rectangle.into_path(0.1); - fill_path(scene, &rec_bez_path, &affine, &fill_brush); - stroke_path(scene, &rec_bez_path, &affine, data.line_width.0, &line_brush); + fill_path(scene, &rec_bez_path, &fill_brush); + stroke_path(scene, &rec_bez_path, data.line_width.0, &line_brush); } } DrawCommand::OutlineFillPath(data) => { - draw_path(scene, &data.path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.fill_style, + None, + &tiny_vg.color_table, + override_color, + ); draw_path( scene, &data.path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -206,6 +229,7 @@ pub(crate) fn draw_tiny_vg( DrawCommand::TextHint(_data) => {} } } - scene.reset_transform(); + + scene.restore_state(scene_state); } } diff --git a/crates/craft_renderer/src/vello_hybrid/mod.rs b/crates/craft_renderer/src/vello_hybrid/mod.rs index 091d7a79..282415d4 100644 --- a/crates/craft_renderer/src/vello_hybrid/mod.rs +++ b/crates/craft_renderer/src/vello_hybrid/mod.rs @@ -1,34 +1,37 @@ mod render_context; mod tinyvg; -use crate::renderer::{RenderCommand, RenderList, Renderer as CraftRenderer, SortedCommands, TextScroll}; +use std::any::Any; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + use chrono::{DateTime, Utc}; -use craft_primitives::geometry::Rectangle; use craft_primitives::Color; +use craft_primitives::geometry::Rectangle; use craft_resource_manager::resource::Resource; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; +use craft_resource_manager::{ResourceId, ResourceManager}; use kurbo::{Affine, Stroke}; use peniko::kurbo::Shape; -use std::any::Any; -use std::collections::{HashMap, HashSet}; -use std::sync::Arc; +use peniko::{BlendMode, Compose, Fill, Mix}; use vello_common::color::PremulRgba8; +use vello_common::filter_effects::{Filter, FilterFunction}; use vello_common::glyph::Glyph; -use vello_common::paint::ImageId; -use vello_common::paint::{ImageSource, PaintType}; +use vello_common::paint::{ImageId, ImageSource, PaintType}; use vello_common::pixmap::Pixmap; use vello_common::{kurbo, peniko}; -use vello_hybrid::RenderSize; -use vello_hybrid::{RenderTargetConfig, Renderer}; +use vello_hybrid::{RenderSize, RenderTargetConfig, Renderer, Scene}; use wgpu::TextureFormat; use winit::window::Window; -use crate::text_renderer_data::TextRenderLine; -use crate::vello_hybrid::render_context::RenderContext; -use crate::vello_hybrid::render_context::RenderSurface; +use crate::RenderCommand; +use crate::helpers::brush_to_paint; +use crate::render_command::{BoxShadowCmd, PushLayerCmd}; +use crate::render_list::RenderList; +use crate::renderer::Renderer as CraftRenderer; +use crate::sort_commands::SortedCommands; +use crate::text_renderer_data::{TextRenderLine, TextScroll}; +use crate::vello_hybrid::render_context::{RenderContext, RenderSurface}; use crate::vello_hybrid::tinyvg::draw_tiny_vg; -use crate::Brush; -use vello_hybrid::Scene; pub struct ActiveRenderState { // The fields MUST be in this order, so that the surface is dropped before the window @@ -61,7 +64,7 @@ pub struct VelloHybridRenderer { scene: Scene, surface_clear_color: Color, - images: HashMap>)>, + images: HashMap>)>, } fn create_vello_renderer(render_cx: &RenderContext, surface: &RenderSurface) -> Renderer { @@ -107,7 +110,9 @@ impl VelloHybridRenderer { .await; // Create a vello Renderer for the surface (using its device id) - vello_renderer.renderers.resize_with(vello_renderer.context.devices.len(), || None); + vello_renderer + .renderers + .resize_with(vello_renderer.context.devices.len(), || None); vello_renderer.renderers[0].get_or_insert_with(|| create_vello_renderer(&vello_renderer.context, &surface)); // Save the Window and Surface to a state variable @@ -126,6 +131,53 @@ fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color) { scene.fill_rect(&rectangle.to_kurbo()); } +fn draw_box_shadow(scene: &mut Scene, box_shadow: &BoxShadowCmd) { + let scene_state = scene.save_current_state(); + + let radius = box_shadow.blur_radius / 2.0; + let filter = Some(Filter::from_function(FilterFunction::Blur { + radius: box_shadow.blur_radius as f32, + })); + + if box_shadow.inset { + let mut clip_path = kurbo::BezPath::new(); + let outline_rect = box_shadow.border_box.expand((radius * 3.0) as f32).to_kurbo(); + clip_path.extend(&outline_rect.to_path(0.1)); + clip_path.extend(&box_shadow.path); + scene.push_layer(Some(&box_shadow.outline), None, None, None, filter); + scene.set_fill_rule(Fill::EvenOdd); + scene.set_paint(box_shadow.color); + scene.fill_path(&clip_path); + scene.pop_layer(); + scene.set_fill_rule(Fill::NonZero); + } else { + scene.push_layer( + None, + Some(BlendMode::new(Mix::Normal, Compose::SrcOver)), + None, + None, + filter, + ); + + scene.set_transform(scene_state.transform * Affine::translate(box_shadow.offset)); + + scene.set_paint(box_shadow.color); + scene.fill_path(&box_shadow.path); + + scene.set_transform(scene_state.transform); + + scene.set_blend_mode(BlendMode::new(Mix::Normal, Compose::DestOut)); + scene.set_paint(Color::WHITE); + scene.fill_path(&box_shadow.outline); + + scene.set_blend_mode(BlendMode::new(Mix::Normal, Compose::SrcOver)); + + scene.pop_layer(); + } + + scene.restore_state(scene_state); +} + impl CraftRenderer for VelloHybridRenderer { fn surface_width(&self) -> f32 { match &self.state { @@ -148,7 +200,8 @@ impl CraftRenderer for VelloHybridRenderer { }; render_state.window_height = height; render_state.window_width = width; - self.context.resize_surface(&mut render_state.surface, width as u32, height as u32); + self.context + .resize_surface(&mut render_state.surface, width as u32, height as u32); self.scene = Scene::new(width as u16, height as u16); } @@ -178,13 +231,21 @@ impl CraftRenderer for VelloHybridRenderer { let width = surface.config.width; let height = surface.config.height; - vello_draw_rect(&mut self.scene, Rectangle::new(0.0, 0.0, width as f32, height as f32), Color::WHITE); + self.scene.set_transform(Affine::IDENTITY); + + vello_draw_rect( + &mut self.scene, + Rectangle::new(0.0, 0.0, width as f32, height as f32), + Color::WHITE, + ); let renderer = self.renderers[surface.dev_id].as_mut().unwrap(); let device_handle = &self.context.devices[surface.dev_id]; - let mut encoder = device_handle.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Blit Textures onto a Texture Atlas Encoder"), - }); + let mut encoder = device_handle + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Blit Textures onto a Texture Atlas Encoder"), + }); let mut images_were_uploaded = false; @@ -194,16 +255,19 @@ impl CraftRenderer for VelloHybridRenderer { let scene = &mut self.scene; match command { - RenderCommand::DrawRect(rectangle, fill_color) => { - vello_draw_rect(scene, *rectangle, *fill_color); + RenderCommand::SetTransform(cmd) => { + self.scene.set_transform(cmd.transform); } - RenderCommand::DrawRectOutline(rectangle, outline_color, thickness) => { - self.scene.set_stroke(Stroke::new(*thickness)); - self.scene.set_paint(PaintType::from(*outline_color)); - self.scene.stroke_rect(&rectangle.to_kurbo()); + RenderCommand::DrawRect(cmd) => { + vello_draw_rect(scene, cmd.rect, cmd.color); } - RenderCommand::DrawImage(rectangle, resource_identifier) => { - let resource = resource_manager.get(resource_identifier); + RenderCommand::DrawRectOutline(cmd) => { + self.scene.set_stroke(Stroke::new(cmd.thickness)); + self.scene.set_paint(PaintType::from(cmd.outline_color)); + self.scene.stroke_rect(&cmd.rect.to_kurbo()); + } + RenderCommand::DrawImage(cmd) => { + let resource = resource_manager.get(&cmd.resource_id); if let Some(resource) = resource && let Resource::Image(resource) = resource.as_ref() @@ -213,13 +277,13 @@ impl CraftRenderer for VelloHybridRenderer { let image = &resource.image; // There is an image, and it hasn't expired. - let image_id = if let Some(stored_image) = self.images.get(resource_identifier) + let image_id = if let Some(stored_image) = self.images.get(&cmd.resource_id) && stored_image.1 == expiration_time { stored_image.0 } else { // There is an image, but it expired. - if let Some(stored_image) = self.images.get(resource_identifier) { + if let Some(stored_image) = self.images.get(&cmd.resource_id) { expired_images.insert(stored_image.0); } @@ -248,37 +312,41 @@ impl CraftRenderer for VelloHybridRenderer { &mut encoder, &pixmap, ); - self.images.insert(resource_identifier.clone(), (image_id, expiration_time)); + self.images.insert(cmd.resource_id.clone(), (image_id, expiration_time)); image_id }; seen_images.insert(image_id); + let scene_state = scene.save_current_state(); let mut transform = Affine::IDENTITY; - transform = - transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + transform = transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); transform = transform.pre_scale_non_uniform( - rectangle.width as f64 / image.width() as f64, - rectangle.height as f64 / image.height() as f64, + cmd.rect.width as f64 / image.width() as f64, + cmd.rect.height as f64 / image.height() as f64, ); - scene.set_transform(transform); + scene.set_transform(scene_state.transform * transform); scene.set_paint(PaintType::Image(vello_common::paint::Image { - image: ImageSource::OpaqueId(image_id), + image: ImageSource::OpaqueId { + id: image_id, + may_have_opacities: true, + }, sampler: Default::default(), })); scene.fill_rect(&kurbo::Rect::new(0.0, 0.0, image.width() as f64, image.height() as f64)); - scene.reset_transform(); + + scene.restore_state(scene_state); } } - RenderCommand::DrawText(text_render, rect, text_scroll, show_cursor) => { + RenderCommand::DrawText(cmd) => { let text_transform = - Affine::default().with_translation(kurbo::Vec2::new(rect.x as f64, rect.y as f64)); - let scroll = text_scroll.unwrap_or(TextScroll::default()).scroll_y; + Affine::default().with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + let scroll = cmd.text_scroll.unwrap_or(TextScroll::default()).scroll_y; let text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); - let c = text_render.upgrade(); + let c = cmd.data.upgrade(); if c.is_none() { return; } @@ -301,7 +369,7 @@ impl CraftRenderer for VelloHybridRenderer { for item in &line.items { if let Some(first_glyph) = item.glyphs.first() { // Cull the glyphs vertically that are outside the window - let gy = first_glyph.y + rect.y - scroll; + let gy = first_glyph.y + cmd.rect.y - scroll; if gy < window.y { skip_line = true; break; @@ -319,8 +387,8 @@ impl CraftRenderer for VelloHybridRenderer { cull_and_process(&mut |line: &TextRenderLine| { for (background, color) in &line.backgrounds { let background_rect = Rectangle { - x: background.x + rect.x, - y: -scroll + background.y + rect.y, + x: background.x + cmd.rect.x, + y: -scroll + background.y + cmd.rect.y, width: background.width, height: background.height, }; @@ -329,8 +397,8 @@ impl CraftRenderer for VelloHybridRenderer { for (selection, selection_color) in &line.selections { let selection_rect = Rectangle { - x: selection.x + rect.x, - y: -scroll + selection.y + rect.y, + x: selection.x + cmd.rect.x, + y: -scroll + selection.y + cmd.rect.y, width: selection.width, height: selection.height, }; @@ -338,22 +406,25 @@ impl CraftRenderer for VelloHybridRenderer { } }); + let scene_state = scene.save_current_state(); + scene.set_transform(scene_state.transform * text_transform); + cull_and_process(&mut |line: &TextRenderLine| { for item in &line.items { if let Some(underline) = &item.underline { - scene.set_transform(text_transform); scene.set_stroke(Stroke::new(underline.width.into())); scene.set_paint(PaintType::from(underline.brush.color)); scene.stroke_path(&underline.line.to_path(0.1)); } scene.set_paint(PaintType::from( - text_render.override_brush.map(|b| b.color).unwrap_or_else(|| item.brush.color), + text_render + .override_brush + .map(|b| b.color) + .unwrap_or_else(|| item.brush.color), )); - scene.reset_transform(); - let glyph_run_builder = - scene.glyph_run(&item.font).font_size(item.font_size).glyph_transform(text_transform); + let glyph_run_builder = scene.glyph_run(&item.font).font_size(item.font_size); glyph_run_builder.fill_glyphs(item.glyphs.iter().map(|glyph| Glyph { id: glyph.id, x: glyph.x, @@ -362,46 +433,62 @@ impl CraftRenderer for VelloHybridRenderer { } }); - if *show_cursor && let Some((cursor, cursor_color)) = &text_render.cursor { + scene.restore_state(scene_state); + + if cmd.show_cursor + && let Some((cursor, cursor_color)) = &text_render.cursor + { let cursor_rect = Rectangle { - x: cursor.x + rect.x, - y: -scroll + cursor.y + rect.y, + x: cursor.x + cmd.rect.x, + y: -scroll + cursor.y + cmd.rect.y, width: cursor.width, height: cursor.height, }; vello_draw_rect(scene, cursor_rect, *cursor_color); } } - RenderCommand::DrawTinyVg(rectangle, resource_identifier, override_color) => { - draw_tiny_vg(scene, *rectangle, &resource_manager, resource_identifier.clone(), override_color); - } - RenderCommand::PushLayer(rect) => { - let clip_path = Some( - kurbo::Rect::from_origin_size( - kurbo::Point::new(rect.x as f64, rect.y as f64), - kurbo::Size::new(rect.width as f64, rect.height as f64), - ) - .into_path(0.1), + RenderCommand::DrawTinyVg(cmd) => { + draw_tiny_vg( + scene, + cmd.rect, + &resource_manager, + cmd.resource_id.clone(), + &cmd.override_color, ); - scene.push_layer(clip_path.as_ref(), None, None, None); + } + RenderCommand::PushLayer(cmd) => { + let clip_path = match cmd { + PushLayerCmd::BezPath(path) => path, + PushLayerCmd::Rect(rect) => &rect.to_kurbo().into_path(0.1), + }; + + scene.push_layer(Some(clip_path), None, None, None, None); } RenderCommand::PopLayer => { scene.pop_layer(); } - RenderCommand::FillBezPath(path, brush) => { - scene.set_paint(brush_to_paint(brush)); - scene.fill_path(path); + RenderCommand::FillBezPath(cmd) => { + scene.set_paint(brush_to_paint(&cmd.brush)); + scene.fill_path(&cmd.path); } - _ => {} + + RenderCommand::StartOverlay => {} + RenderCommand::EndOverlay => {} + RenderCommand::BoxShadowCmd(cmd) => draw_box_shadow(scene, cmd), } }); - let mut to_remove: Vec = Vec::new(); + let mut to_remove: Vec = Vec::new(); for expired_image_id in &expired_images { // Note: Expired images will have an entry in the images hashmap, but with a new ImageId. // Meaning, that we need to delete the detached/abandoned expired image id here. - renderer.destroy_image(&device_handle.device, &device_handle.queue, &mut encoder, *expired_image_id); + renderer.destroy_image( + &device_handle.device, + &device_handle.queue, + &mut encoder, + *expired_image_id, + ); images_were_uploaded = true; } @@ -446,22 +533,36 @@ impl CraftRenderer for VelloHybridRenderer { let device_handle = &self.context.devices[surface.dev_id]; // Get the surface's texture - let surface_texture = surface.surface.get_current_texture().expect("failed to get surface texture"); + let surface_texture = surface + .surface + .get_current_texture() + .expect("failed to get surface texture"); let render_size = RenderSize { width: surface.config.width, height: surface.config.height, }; - let mut encoder = device_handle.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Vello Render to Surface pass"), - }); - let texture_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = device_handle + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Vello Render to Surface pass"), + }); + let texture_view = surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); self.renderers[surface.dev_id] .as_mut() .unwrap() - .render(&self.scene, &device_handle.device, &device_handle.queue, &mut encoder, &render_size, &texture_view) + .render( + &self.scene, + &device_handle.device, + &device_handle.queue, + &mut encoder, + &render_size, + &texture_view, + ) .unwrap(); device_handle.queue.submit([encoder.finish()]); @@ -472,14 +573,3 @@ impl CraftRenderer for VelloHybridRenderer { self.scene.reset(); } } - -fn brush_to_paint(brush: &Brush) -> PaintType { - match brush { - Brush::Color(color) => PaintType::from(*color), - Brush::Gradient(gradient) => { - // Paint::Gradient does not exist yet, so we need to come back and fix this later. - let color = gradient.stops.first().map(|c| c.color.to_alpha_color()).unwrap_or(Color::BLACK); - PaintType::from(color) - } - } -} diff --git a/crates/craft_renderer/src/vello_hybrid/render_context.rs b/crates/craft_renderer/src/vello_hybrid/render_context.rs index 63d1d62a..de6dcdb4 100644 --- a/crates/craft_renderer/src/vello_hybrid/render_context.rs +++ b/crates/craft_renderer/src/vello_hybrid/render_context.rs @@ -6,14 +6,10 @@ reason = "This is a shared module between examples; not all examples use all functionality from it" )] -use winit::window::Window; - use vello_hybrid::{RenderTargetConfig, Renderer}; -use wgpu::{ - Adapter, Device, Features, Instance, Limits, MemoryHints, Queue, Surface, SurfaceConfiguration, SurfaceTarget, - TextureFormat, -}; +use wgpu::{Adapter, Device, Features, Instance, Limits, MemoryHints, Queue, Surface, SurfaceConfiguration, SurfaceTarget, TextureFormat}; use winit::event_loop::ActiveEventLoop; +use winit::window::Window; /// Helper function that creates a Winit window and returns it (wrapped in an Arc for sharing) pub(crate) fn create_winit_window( @@ -94,7 +90,9 @@ impl RenderContext { format: TextureFormat, ) -> RenderSurface<'w> { self.create_render_surface( - self.instance.create_surface(window.into()).expect("Error creating surface"), + self.instance + .create_surface(window.into()) + .expect("Error creating surface"), width, height, present_mode, @@ -154,7 +152,12 @@ impl RenderContext { /// Finds or creates a compatible device handle id. pub(crate) async fn device(&mut self, compatible_surface: Option<&Surface<'_>>) -> Option { let compatible = match compatible_surface { - Some(s) => self.devices.iter().enumerate().find(|(_, d)| d.adapter.is_surface_supported(s)).map(|(i, _)| i), + Some(s) => self + .devices + .iter() + .enumerate() + .find(|(_, d)| d.adapter.is_surface_supported(s)) + .map(|(i, _)| i), None => (!self.devices.is_empty()).then_some(0), }; if compatible.is_none() { @@ -165,7 +168,9 @@ impl RenderContext { /// Creates a compatible device handle id. async fn new_device(&mut self, compatible_surface: Option<&Surface<'_>>) -> Option { - let adapter = wgpu::util::initialize_adapter_from_env_or_default(&self.instance, compatible_surface).await.ok()?; + let adapter = wgpu::util::initialize_adapter_from_env_or_default(&self.instance, compatible_surface) + .await + .ok()?; #[cfg(feature = "vello_hybrid_renderer_webgl")] let limits = Limits { max_color_attachments: 4, @@ -177,15 +182,14 @@ impl RenderContext { let limits = Limits::default(); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: None, - required_features: Features::empty(), - required_limits: limits, - memory_hints: MemoryHints::default(), - trace: Default::default(), - }, - ) + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: Features::empty(), + required_limits: limits, + experimental_features: Default::default(), + memory_hints: MemoryHints::default(), + trace: Default::default(), + }) .await .ok()?; let device_handle = DeviceHandle { diff --git a/crates/craft_renderer/src/vello_hybrid/tinyvg.rs b/crates/craft_renderer/src/vello_hybrid/tinyvg.rs index b87ed8d6..52b7697d 100644 --- a/crates/craft_renderer/src/vello_hybrid/tinyvg.rs +++ b/crates/craft_renderer/src/vello_hybrid/tinyvg.rs @@ -1,27 +1,26 @@ +use std::sync::Arc; + +use craft_primitives::Color; use craft_primitives::geometry::Rectangle; -use crate::vello_hybrid::brush_to_paint; -use crate::renderer::Brush; use craft_resource_manager::resource::Resource; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; -use craft_primitives::Color; +use craft_resource_manager::{ResourceId, ResourceManager}; use peniko::kurbo::{Affine, BezPath, Line, Shape, Stroke}; -use peniko::{kurbo, Fill}; -use std::sync::Arc; +use peniko::{Fill, kurbo}; use tinyvg_rs::color_table::ColorTable; use tinyvg_rs::commands::{DrawCommand, Path, PathCommand, Segment, Style}; use tinyvg_rs::common::Unit; use vello_hybrid::Scene; -use crate::tinyvg_helpers; -fn stroke_path(scene: &mut Scene, bez_path: &BezPath, affine: &Affine, line_width: f64, brush: &Brush) { +use crate::vello_hybrid::brush_to_paint; +use crate::{Brush, tinyvg_helpers}; + +fn stroke_path(scene: &mut Scene, bez_path: &BezPath, line_width: f64, brush: &Brush) { scene.set_stroke(Stroke::new(line_width)); - scene.set_transform(*affine); scene.set_paint(brush_to_paint(brush)); scene.stroke_path(bez_path); } -fn fill_path(scene: &mut Scene, bez_path: &BezPath, affine: &Affine, brush: &Brush) { - scene.set_transform(*affine); +fn fill_path(scene: &mut Scene, bez_path: &BezPath, brush: &Brush) { scene.set_paint(brush_to_paint(brush)); scene.set_fill_rule(Fill::EvenOdd); scene.fill_path(bez_path); @@ -33,15 +32,14 @@ pub(crate) fn draw_path( fill_style: &Style, line_width: Option<&Unit>, color_table: &ColorTable, - affine: &Affine, override_color: &Option, ) { let (bezier_path, brush) = tinyvg_helpers::assemble_path(path, fill_style, color_table, override_color); if let Some(line_width) = line_width { - stroke_path(scene, &bezier_path, affine, line_width.0, &brush); + stroke_path(scene, &bezier_path, line_width.0, &brush); } else { - fill_path(scene, &bezier_path, affine, &brush); + fill_path(scene, &bezier_path, &brush); } } @@ -49,10 +47,10 @@ pub(crate) fn draw_tiny_vg( scene: &mut Scene, rectangle: Rectangle, resource_manager: &Arc, - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, override_color: &Option, ) { - let resource = resource_manager.get(&resource_identifier); + let resource = resource_manager.get(&resource_id); if resource.is_none() { return; } @@ -64,7 +62,9 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let scene_state = scene.save_current_state(); + + let vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -76,12 +76,14 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + let vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + let vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + scene.set_transform(scene_state.transform * vg_transform); + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -97,18 +99,25 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path(scene, &path, &data.style, None, &tiny_vg.color_table, override_color); } DrawCommand::FillRectangles(data) => { let brush = tinyvg_helpers::get_brush(&data.style, &tiny_vg.color_table, override_color); for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - fill_path(scene, &rectangle.into_path(0.1), &affine, &brush); + fill_path(scene, &rectangle.into_path(0.1), &brush); } } DrawCommand::FillPath(data) => { - draw_path(scene, &data.path, &data.style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.style, + None, + &tiny_vg.color_table, + override_color, + ); } DrawCommand::DrawLines(data) => { let brush = tinyvg_helpers::get_brush(&data.line_style, &tiny_vg.color_table, override_color); @@ -118,7 +127,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); } } DrawCommand::DrawLineLoop(data) => { @@ -126,9 +135,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -137,9 +148,11 @@ pub(crate) fn draw_tiny_vg( let mut start = data.points[0]; for point in &data.points { - let line = - Line::new(tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point)); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + let line = Line::new( + tinyvg_helpers::to_kurbo_point(start), + tinyvg_helpers::to_kurbo_point(*point), + ); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -150,7 +163,6 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -167,14 +179,20 @@ pub(crate) fn draw_tiny_vg( let path = Path { segments: vec![segment], }; - draw_path(scene, &path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &path, + &data.fill_style, + None, + &tiny_vg.color_table, + override_color, + ); draw_path( scene, &path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -185,19 +203,25 @@ pub(crate) fn draw_tiny_vg( let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); let rec_bez_path = rectangle.into_path(0.1); - fill_path(scene, &rec_bez_path, &affine, &fill_brush); - stroke_path(scene, &rec_bez_path, &affine, data.line_width.0, &line_brush); + fill_path(scene, &rec_bez_path, &fill_brush); + stroke_path(scene, &rec_bez_path, data.line_width.0, &line_brush); } } DrawCommand::OutlineFillPath(data) => { - draw_path(scene, &data.path, &data.fill_style, None, &tiny_vg.color_table, &affine, override_color); + draw_path( + scene, + &data.path, + &data.fill_style, + None, + &tiny_vg.color_table, + override_color, + ); draw_path( scene, &data.path, &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -208,6 +232,6 @@ pub(crate) fn draw_tiny_vg( } } - scene.reset_transform(); + scene.restore_state(scene_state); } } diff --git a/crates/craft_resource_manager/Cargo.toml b/crates/craft_resource_manager/Cargo.toml index 0cc4a70a..99846e32 100644 --- a/crates/craft_resource_manager/Cargo.toml +++ b/crates/craft_resource_manager/Cargo.toml @@ -25,7 +25,7 @@ optional = true [target.'cfg(target_os = "android")'.dependencies.reqwest] workspace = true default-features = false -features = ["rustls-tls"] +features = ["rustls"] optional = true [dependencies.image] diff --git a/crates/craft_resource_manager/src/identifier.rs b/crates/craft_resource_manager/src/identifier.rs index 314cb629..52336c7f 100644 --- a/crates/craft_resource_manager/src/identifier.rs +++ b/crates/craft_resource_manager/src/identifier.rs @@ -1,21 +1,20 @@ -use crate::ResourceIdentifier::{Bytes, File}; - -#[cfg(feature = "http_client")] -use crate::ResourceIdentifier::Url; - use std::fmt::Display; use std::path::PathBuf; use std::{fmt, fs}; +#[cfg(feature = "http_client")] +use crate::ResourceId::Url; +use crate::ResourceId::{Bytes, File}; + #[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub enum ResourceIdentifier { +pub enum ResourceId { #[cfg(feature = "http_client")] Url(String), File(PathBuf), Bytes(&'static [u8]), } -impl Display for ResourceIdentifier { +impl Display for ResourceId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { #[cfg(feature = "http_client")] @@ -26,8 +25,8 @@ impl Display for ResourceIdentifier { } } -impl ResourceIdentifier { - pub async fn fetch_data_from_resource_identifier(&self) -> Option> { +impl ResourceId { + pub async fn fetch_data_from_resource_id(&self) -> Option> { match self { #[cfg(feature = "http_client")] Url(url) => { diff --git a/crates/craft_resource_manager/src/image.rs b/crates/craft_resource_manager/src/image.rs index e27c56e3..713ab2b4 100644 --- a/crates/craft_resource_manager/src/image.rs +++ b/crates/craft_resource_manager/src/image.rs @@ -1,6 +1,7 @@ -use crate::resource_data::ResourceData; use image::{EncodableLayout, RgbaImage}; +use crate::resource_data::ResourceData; + #[derive(Debug)] pub struct ImageResource { pub common_data: ResourceData, diff --git a/crates/craft_resource_manager/src/lib.rs b/crates/craft_resource_manager/src/lib.rs index d5fc325e..83fd9923 100644 --- a/crates/craft_resource_manager/src/lib.rs +++ b/crates/craft_resource_manager/src/lib.rs @@ -8,30 +8,29 @@ pub(crate) mod tinyvg_resource; pub mod resource_event; -pub use crate::identifier::ResourceIdentifier; +use std::any::Any; +use std::future::Future; +use std::io::Cursor; +use std::pin::Pin; +use std::sync::Arc; + +use ::image::ImageReader; +use craft_logging::info; +use craft_runtime::{CraftRuntimeHandle, Sender}; + +pub use crate::identifier::ResourceId; use crate::image::ImageResource; +use crate::lock_free_map::LockFreeMap; use crate::resource::Resource; use crate::resource_data::ResourceData; use crate::resource_event::ResourceEvent; use crate::resource_type::ResourceType; -use craft_logging::info; - -use craft_runtime::Sender; - -use crate::lock_free_map::LockFreeMap; use crate::tinyvg_resource::TinyVgResource; -use ::image::ImageReader; -use craft_runtime::CraftRuntimeHandle; -use std::any::Any; -use std::future::Future; -use std::io::Cursor; -use std::pin::Pin; -use std::sync::Arc; pub type ResourceFuture = Pin> + Send + Sync>>; pub struct ResourceManager { - resources: LockFreeMap, + resources: LockFreeMap, pub(crate) runtime: CraftRuntimeHandle, } @@ -42,40 +41,39 @@ impl ResourceManager { runtime: craft_runtime_handle, } } + // TODO: FIx the duplicate code in this function. #[cfg(target_arch = "wasm32")] pub fn async_download_resource_and_send_message_on_finish + 'static>( &self, app_sender: Sender, - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, resource_type: ResourceType, ) { - let resource_identifier_copy = resource_identifier.clone(); + let resource_id_copy = resource_id.clone(); let resource_type_copy = resource_type; match &resource_type_copy { ResourceType::Image => { - let resource_identifier = resource_identifier.clone(); + let resource_id = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let image = resource_identifier.fetch_data_from_resource_identifier().await; + let image = resource_id.fetch_data_from_resource_id().await; if let Some(image_resource) = &image { let bytes = image_resource; let cursor = Cursor::new(&bytes); - let reader = ImageReader::new(cursor).with_guessed_format().expect("Failed to guess format"); + let reader = ImageReader::new(cursor) + .with_guessed_format() + .expect("Failed to guess format"); let size = reader.into_dimensions().unwrap_or_default(); - let generic_resource = ResourceData::new( - resource_identifier.clone(), - Some(bytes.to_vec()), - None, - ResourceType::Image, - ); + let generic_resource = + ResourceData::new(resource_id.clone(), Some(bytes.to_vec()), None, ResourceType::Image); info!("Image downloaded"); let resource = Resource::Image(Arc::new(ImageResource::new(size.0, size.1, generic_resource))); app_sender_copy - .send(ResourceEvent::Loaded(resource_identifier_copy, ResourceType::Image, resource).into()) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::Image, resource).into()) .await .expect("Failed to send added resource event"); } @@ -83,19 +81,19 @@ impl ResourceManager { self.runtime.spawn(f); } ResourceType::Font => { - let resource = resource_identifier.clone(); + let resource = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let mut bytes = resource.clone().fetch_data_from_resource_identifier().await; + let mut bytes = resource.clone().fetch_data_from_resource_id().await; if let Some(font_bytes) = bytes.take() { let generic_resource = - ResourceData::new(resource_identifier.clone(), Some(font_bytes), None, ResourceType::Font); + ResourceData::new(resource_id.clone(), Some(font_bytes), None, ResourceType::Font); info!("Font downloaded"); let resource = Resource::Font(generic_resource); app_sender_copy - .send(ResourceEvent::Loaded(resource_identifier_copy, ResourceType::Font, resource).into()) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::Font, resource).into()) .await .expect("Failed to send added resource event"); } @@ -103,24 +101,18 @@ impl ResourceManager { self.runtime.spawn(f); } ResourceType::TinyVg => { - let resource = resource_identifier.clone(); + let resource = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let bytes = resource.clone().fetch_data_from_resource_identifier().await; + let bytes = resource.clone().fetch_data_from_resource_id().await; if let Some(bytes) = bytes { - let generic_resource = ResourceData::new( - resource_identifier.clone(), - Some(bytes.to_vec()), - None, - ResourceType::TinyVg, - ); + let generic_resource = + ResourceData::new(resource_id.clone(), Some(bytes.to_vec()), None, ResourceType::TinyVg); let resource = Resource::TinyVg(TinyVgResource::new(generic_resource)); info!("TinyVG downloaded"); app_sender_copy - .send( - ResourceEvent::Loaded(resource_identifier_copy, ResourceType::TinyVg, resource).into(), - ) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::TinyVg, resource).into()) .await .expect("Failed to send added resource event"); } @@ -134,35 +126,33 @@ impl ResourceManager { pub fn async_download_resource_and_send_message_on_finish + Send + 'static>( &self, app_sender: Sender, - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, resource_type: ResourceType, ) { - let resource_identifier_copy = resource_identifier.clone(); + let resource_id_copy = resource_id.clone(); let resource_type_copy = resource_type; match &resource_type_copy { ResourceType::Image => { - let resource_identifier = resource_identifier.clone(); + let resource_id = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let image = resource_identifier.fetch_data_from_resource_identifier().await; + let image = resource_id.fetch_data_from_resource_id().await; if let Some(image_resource) = &image { let bytes = image_resource; let cursor = Cursor::new(&bytes); - let reader = ImageReader::new(cursor).with_guessed_format().expect("Failed to guess format"); + let reader = ImageReader::new(cursor) + .with_guessed_format() + .expect("Failed to guess format"); let size = reader.into_dimensions().unwrap_or_default(); - let generic_resource = ResourceData::new( - resource_identifier.clone(), - Some(bytes.to_vec()), - None, - ResourceType::Image, - ); + let generic_resource = + ResourceData::new(resource_id.clone(), Some(bytes.to_vec()), None, ResourceType::Image); info!("Image downloaded"); let resource = Resource::Image(Arc::new(ImageResource::new(size.0, size.1, generic_resource))); app_sender_copy - .send(ResourceEvent::Loaded(resource_identifier_copy, ResourceType::Image, resource).into()) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::Image, resource).into()) .await .expect("Failed to send added resource event"); } @@ -170,19 +160,19 @@ impl ResourceManager { self.runtime.spawn(f); } ResourceType::Font => { - let resource = resource_identifier.clone(); + let resource = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let mut bytes = resource.clone().fetch_data_from_resource_identifier().await; + let mut bytes = resource.clone().fetch_data_from_resource_id().await; if let Some(font_bytes) = bytes.take() { let generic_resource = - ResourceData::new(resource_identifier.clone(), Some(font_bytes), None, ResourceType::Font); + ResourceData::new(resource_id.clone(), Some(font_bytes), None, ResourceType::Font); info!("Font downloaded"); let resource = Resource::Font(generic_resource); app_sender_copy - .send(ResourceEvent::Loaded(resource_identifier_copy, ResourceType::Font, resource).into()) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::Font, resource).into()) .await .expect("Failed to send added resource event"); } @@ -190,24 +180,18 @@ impl ResourceManager { self.runtime.spawn(f); } ResourceType::TinyVg => { - let resource = resource_identifier.clone(); + let resource = resource_id.clone(); let app_sender_copy = app_sender.clone(); let f = async move { - let bytes = resource.clone().fetch_data_from_resource_identifier().await; + let bytes = resource.clone().fetch_data_from_resource_id().await; if let Some(bytes) = bytes { - let generic_resource = ResourceData::new( - resource_identifier.clone(), - Some(bytes.to_vec()), - None, - ResourceType::TinyVg, - ); + let generic_resource = + ResourceData::new(resource_id.clone(), Some(bytes.to_vec()), None, ResourceType::TinyVg); let resource = Resource::TinyVg(TinyVgResource::new(generic_resource)); info!("TinyVG downloaded"); app_sender_copy - .send( - ResourceEvent::Loaded(resource_identifier_copy, ResourceType::TinyVg, resource).into(), - ) + .send(ResourceEvent::Loaded(resource_id_copy, ResourceType::TinyVg, resource).into()) .await .expect("Failed to send added resource event"); } @@ -217,15 +201,15 @@ impl ResourceManager { } } - pub fn contains(&self, resource_identifier: &ResourceIdentifier) -> bool { - self.resources.contains(resource_identifier) + pub fn contains(&self, resource_id: &ResourceId) -> bool { + self.resources.contains(resource_id) } - pub fn get(&self, resource_identifier: &ResourceIdentifier) -> Option> { - self.resources.get(resource_identifier) + pub fn get(&self, resource_id: &ResourceId) -> Option> { + self.resources.get(resource_id) } - pub fn insert(&self, resource_identifier: ResourceIdentifier, resource: Arc) { - self.resources.insert(resource_identifier, resource); + pub fn insert(&self, resource_id: ResourceId, resource: Arc) { + self.resources.insert(resource_id, resource); } } diff --git a/crates/craft_resource_manager/src/lock_free_map.rs b/crates/craft_resource_manager/src/lock_free_map.rs index 993bc3e8..c6bb2728 100644 --- a/crates/craft_resource_manager/src/lock_free_map.rs +++ b/crates/craft_resource_manager/src/lock_free_map.rs @@ -1,8 +1,8 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::ptr; -use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; pub struct Node { pub key: K, @@ -18,12 +18,16 @@ pub struct Inner { impl Inner { pub fn new(size: usize) -> Self { let size = size.next_power_of_two().max(1); - let buckets = (0..size).map(|_| AtomicPtr::new(ptr::null_mut())).collect::>().into_boxed_slice(); + let buckets = (0..size) + .map(|_| AtomicPtr::new(ptr::null_mut())) + .collect::>() + .into_boxed_slice(); Inner { mask: size - 1, buckets, } } + pub fn bucket(&self, key: &K) -> usize { let mut h = DefaultHasher::new(); key.hash(&mut h); @@ -51,6 +55,7 @@ impl LockFreeMap { count: AtomicUsize::new(0), } } + fn with_root(&self, f: F) -> R where F: FnOnce(&Arc>) -> R, @@ -64,6 +69,7 @@ impl LockFreeMap { res } } + fn resize_if_needed(&self) { let count = self.count.load(Ordering::Relaxed); self.with_root(|inner| { @@ -98,6 +104,7 @@ impl LockFreeMap { } }); } + pub fn insert(&self, key: K, value: Arc) { self.resize_if_needed(); self.with_root(|inner| { @@ -112,6 +119,7 @@ impl LockFreeMap { }); self.count.fetch_add(1, Ordering::Relaxed); } + pub fn get(&self, key: &K) -> Option> { self.with_root(|inner| { let idx = inner.bucket(key); diff --git a/crates/craft_resource_manager/src/resource.rs b/crates/craft_resource_manager/src/resource.rs index 512347ab..22641620 100644 --- a/crates/craft_resource_manager/src/resource.rs +++ b/crates/craft_resource_manager/src/resource.rs @@ -1,8 +1,10 @@ -use crate::image::ImageResource; -use crate::tinyvg_resource::TinyVgResource; use std::sync::Arc; + use image::EncodableLayout; + +use crate::image::ImageResource; use crate::resource_data::ResourceData; +use crate::tinyvg_resource::TinyVgResource; #[derive(Debug)] pub enum Resource { diff --git a/crates/craft_resource_manager/src/resource_data.rs b/crates/craft_resource_manager/src/resource_data.rs index 0d574813..d96f19fc 100644 --- a/crates/craft_resource_manager/src/resource_data.rs +++ b/crates/craft_resource_manager/src/resource_data.rs @@ -1,11 +1,12 @@ -use crate::identifier::ResourceIdentifier; -use crate::resource_type::ResourceType; use chrono::{DateTime, Utc}; +use crate::identifier::ResourceId; +use crate::resource_type::ResourceType; + #[allow(dead_code)] #[derive(Debug)] pub struct ResourceData { - pub(crate) resource_identifier: ResourceIdentifier, + pub(crate) resource_id: ResourceId, pub(crate) data: Option>, pub(crate) resource_type: ResourceType, pub(crate) expiration_time: Option>, @@ -13,13 +14,13 @@ pub struct ResourceData { impl ResourceData { pub(crate) fn new( - resource_identifier: ResourceIdentifier, + resource_id: ResourceId, data: Option>, expiration_time: Option>, resource_type: ResourceType, ) -> Self { ResourceData { - resource_identifier, + resource_id, expiration_time, data, resource_type, diff --git a/crates/craft_resource_manager/src/resource_event.rs b/crates/craft_resource_manager/src/resource_event.rs index 8e65a6df..b72f62fa 100644 --- a/crates/craft_resource_manager/src/resource_event.rs +++ b/crates/craft_resource_manager/src/resource_event.rs @@ -1,10 +1,10 @@ +use crate::ResourceId; use crate::resource::Resource; use crate::resource_type::ResourceType; -use crate::ResourceIdentifier; #[derive(Debug)] pub enum ResourceEvent { - Loaded(ResourceIdentifier, ResourceType, Resource), + Loaded(ResourceId, ResourceType, Resource), #[allow(dead_code)] - UnLoaded(ResourceIdentifier), + UnLoaded(ResourceId), } diff --git a/crates/craft_resource_manager/src/tinyvg_resource.rs b/crates/craft_resource_manager/src/tinyvg_resource.rs index 3690c77c..f4b8842c 100644 --- a/crates/craft_resource_manager/src/tinyvg_resource.rs +++ b/crates/craft_resource_manager/src/tinyvg_resource.rs @@ -1,6 +1,7 @@ -use crate::resource_data::ResourceData; use tinyvg_rs::TinyVg; +use crate::resource_data::ResourceData; + #[derive(Debug)] pub struct TinyVgResource { pub common_data: ResourceData, diff --git a/crates/craft_retained/Cargo.toml b/crates/craft_retained/Cargo.toml index 1c23e391..26d40a29 100644 --- a/crates/craft_retained/Cargo.toml +++ b/crates/craft_retained/Cargo.toml @@ -11,6 +11,10 @@ repository = "https://github.com/craft-gui/craft" [features] dynamic_linking = [] clipboard = ["dep:clipboard-rs"] +vello_cpu_renderer = ["craft_renderer/vello_cpu_renderer"] +vello_hybrid_renderer = ["craft_renderer/vello_hybrid_renderer"] +vello_renderer = ["craft_renderer/vello_renderer"] +http_client = ["craft_resource_manager/http_client"] system_fonts = ["parley/system"] @@ -23,11 +27,11 @@ markdown = ["dep:pulldown-cmark", "code_highlighting", "link"] code_highlighting = ["dep:syntect"] link = ["dep:open"] -default = ["clipboard", "accesskit"] - +default = ["vello_hybrid_renderer", "clipboard", "accesskit"] [dependencies] craft_logging = { path = "../craft_logger", version = "0.1.0" } +craft_undo = {path = "../craft_undo", version = "0.1.1"} smol_str = "0.3.4" @@ -35,13 +39,13 @@ smol_str = "0.3.4" workspace = true [dependencies.accesskit_winit] -version = "0.29.2" +version = "0.32.2" default-features = false features = ["tokio", "rwh_06", "accesskit_unix"] optional = true [dependencies.accesskit] -version = "0.21.1" +version = "0.24.0" default-features = false optional = true @@ -49,8 +53,8 @@ optional = true version = "2.10.0" features = ["std"] -[dependencies.kurbo] -workspace = true +#[dependencies.kurbo] +#workspace = true [dependencies.smallvec] version = "1.15.1" @@ -68,7 +72,7 @@ default-features = false features = ["std"] [target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies.clipboard-rs] -version = "0.3.0" +version = "0.3.1" optional = true [dependencies.pulldown-cmark] @@ -87,7 +91,9 @@ optional = true workspace = true [dependencies.taffy] -version = "0.9.2" +#version = "0.9.2" +git = "https://github.com/AustinMReppert/taffy" +rev = "41af7ddf5806dcf67a3d702fcbe37b340a5cc8b8" default-features = false features = ["std", "taffy_tree", "flexbox", "content_size", "block_layout"] @@ -103,15 +109,17 @@ workspace = true features = ["android-native-activity"] [dependencies.ui-events] -version = "0.2.0" +git = "https://github.com/endoli/ui-events" +rev = "d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7" features = ["kurbo"] [dependencies.ui-events-winit] -version = "0.2.0" +git = "https://github.com/endoli/ui-events" +rev = "d2dc8ba005a21870c5e4a7221cadf08fbf5f9ae7" features = [] [dependencies.parley] -version = "0.7.0" +version = "0.8.0" default-features = false features = ["std"] @@ -121,12 +129,12 @@ default-features = false features = [] [target.'cfg(target_arch = "wasm32")'.dependencies.wasm-bindgen] -version = "0.2.100" +version = "0.2.106" default-features = false features = ["std", "msrv"] [target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] -version = "0.3.77" +version = "0.3.83" default-features = false features = [ "Document", @@ -135,7 +143,7 @@ features = [ ] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.open] -version = "5.3.2" +version = "5.3.3" default-features = false optional = true features = [] @@ -158,4 +166,14 @@ version = "0.1.1" [dependencies.craft_resource_manager] path = "../craft_resource_manager" default-features = false -version = "0.1.1" \ No newline at end of file +version = "0.1.1" + +[dev-dependencies] +libtest-mimic-collect = "0.3.3" + + +[[test]] +name = "counter" +path = "tests/counter.rs" +harness = false +required-features = ["vello_cpu_renderer", "png"] \ No newline at end of file diff --git a/crates/craft_retained/src/accessibility/access_handler.rs b/crates/craft_retained/src/accessibility/access_handler.rs index e491884b..4f8514f1 100644 --- a/crates/craft_retained/src/accessibility/access_handler.rs +++ b/crates/craft_retained/src/accessibility/access_handler.rs @@ -1,16 +1,6 @@ -#[cfg(not(target_arch = "wasm32"))] -use craft_runtime::CraftRuntimeHandle; -use crate::events::internal::InternalMessage; use accesskit::{ActionHandler, ActionRequest}; -use craft_runtime::Sender; -pub(crate) struct CraftAccessHandler { - #[cfg(not(target_arch = "wasm32"))] - #[allow(dead_code)] - pub(crate) runtime_handle: CraftRuntimeHandle, - #[allow(dead_code)] - pub(crate) app_sender: Sender, -} +pub(crate) struct CraftAccessHandler {} impl ActionHandler for CraftAccessHandler { fn do_action(&mut self, _request: ActionRequest) {} diff --git a/crates/craft_retained/src/animations/animation.rs b/crates/craft_retained/src/animations/animation.rs deleted file mode 100644 index 8689b189..00000000 --- a/crates/craft_retained/src/animations/animation.rs +++ /dev/null @@ -1,348 +0,0 @@ -use crate::style::{Style, StyleProperty, Unit}; -use craft_primitives::geometry::TrblRectangle; -use kurbo::{CubicBez, ParamCurve, Point}; -use smallvec::SmallVec; -use std::collections::HashMap; -use std::iter::zip; -use std::time::Duration; -use smol_str::SmolStr; - -#[derive(Clone, Debug)] -pub struct KeyFrame { - /// The action / styles interpolated at `offset_percentage`. - /// Range [0.0, 100.0] - offset_percentage: f32, - - /// The list of styles interpolated to an element at this keyframe. - properties: SmallVec<[StyleProperty; 3]>, -} - -impl KeyFrame { - pub fn new(offset_percentage: f32) -> Self { - KeyFrame { - offset_percentage, - properties: SmallVec::new(), - } - } - - pub fn push(mut self, property: StyleProperty) -> Self { - self.properties.push(property); - self - } -} - -#[derive(Copy, Clone, Debug)] -#[derive(PartialEq)] -pub enum AnimationStatus { - Paused, - Playing, - Scheduled, -} - -/// A cubic bézier curve where P0 and P3 are stuck at (0,0) and (1,1). -#[derive(Clone, Copy, Debug)] -pub struct FixedCubicBezier { - cubic_bez: CubicBez, -} - -impl FixedCubicBezier { - /// Sets P1 and P2 of a fixed cubic bézier curve. - pub fn new(x1: f32, y1: f32, x2: f32, y2: f32) -> Self { - Self { - cubic_bez: CubicBez::new( - Point::new(0.0, 0.0), - Point::new(x1 as f64, y1 as f64), - Point::new(x2 as f64, y2 as f64), - Point::new(1.0, 1.0), - ) - } - } -} - - -/// The motion of an animation modeled with a mathematical function. -#[derive(Default, Copy, Clone, Debug)] -pub enum TimingFunction { - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#linear - #[default] - Linear, - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease - Ease, - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-in - EaseIn, - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-out - EaseOut, - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-in-out - EaseInOut, - /// https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#cubic-beziernumber_01_number_number_01_number - BezierCurve(FixedCubicBezier), -} - -#[derive(Clone, Debug)] -pub struct Animation { - pub name: SmolStr, - pub key_frames: SmallVec<[KeyFrame; 2]>, - pub duration: Duration, - pub timing_function: TimingFunction, - pub loop_amount: LoopAmount, -} - -#[derive(Copy, Clone, Debug)] -pub enum LoopAmount { - Infinite, - Fixed(u32) -} - -impl Animation { - pub fn new(name: &str, duration: Duration, timing_function: TimingFunction) -> Self { - Self { - name: name.into(), - key_frames: SmallVec::new(), - duration, - timing_function, - loop_amount: LoopAmount::Fixed(1), - } - } - - pub fn push(mut self, key_frame: KeyFrame) -> Self { - self.key_frames.push(key_frame); - self - } - - pub fn loop_amount(mut self, loop_amount: LoopAmount) -> Self { - self.loop_amount = loop_amount; - self - } -} - -#[derive(Copy, Clone, Debug)] -pub struct ActiveAnimation { - /// How far into an animation we are. - pub(crate) current: Duration, - /// Tracks the status of an animation, if it is playing, scheduled, or paused. - pub(crate) status: AnimationStatus, - pub(crate) loop_amount: LoopAmount, -} - -/// For damage tracking across recursive calls to `on_animation_frame`. -#[derive(Clone, Copy, Debug, Default)] -pub struct AnimationFlags { - needs_relayout: bool, - has_active_animation: bool, -} - -impl AnimationFlags { - /// OR'd with the provided boolean and the previously stored boolean, to track if an animatable property effects layout. - /// This is used after `on_animation_frame` to optionally recompute the layout. - pub fn set_needs_relayout(&mut self, needs_relayout: bool) { - self.needs_relayout |= needs_relayout; - } - - /// Returns whether we need to perform a relayout or not. - pub fn needs_relayout(&self) -> bool { - self.needs_relayout - } - - /// OR'd with the provided boolean and the previously stored boolean, to track if any animation is active. - pub fn set_has_active_animation(&mut self, has_active_animation: bool) { - self.has_active_animation |= has_active_animation; - } - - /// Returns true if any animation is in the Playing state. - pub fn has_active_animation(&self) -> bool { - self.has_active_animation - } -} - -impl ActiveAnimation { - - /// Advances an active animation, and it is also responsible for tracking the status and element_state. - pub fn tick(&mut self, animation_flags: &mut AnimationFlags, animation: &Animation, delta: Duration) { - if self.status == AnimationStatus::Playing { - self.current += delta; - - let is_completed = self.current >= animation.duration; - - match &mut self.loop_amount { - LoopAmount::Infinite => { - if is_completed { - self.current = Duration::ZERO; - } - } - LoopAmount::Fixed(amount) => { - if is_completed { - *amount -= 1; - - if *amount == 0 { - self.current = Duration::ZERO; - self.status = AnimationStatus::Paused; - animation_flags.set_needs_relayout(true); - } else { - self.current = Duration::ZERO; - } - } - } - } - - } - } - - /// Called after `tick`, and is responsible for using the current animation time and - /// computing an interpolated style from a provided `Animation`. - pub fn compute_style(&mut self, element_style: &Style, animation: &Animation, animation_flags: &mut AnimationFlags) -> Style { - if self.status != AnimationStatus::Playing { - return element_style.clone(); - } - - let pos = Duration::div_duration_f32(self.current, animation.duration); - fn find_keyframe_pair(pos: f32, animation: &Animation) -> (&KeyFrame, &KeyFrame) { - let mut sorted = animation.key_frames.iter().collect::>(); - sorted.sort_unstable_by(|a, b| a.offset_percentage.total_cmp(&b.offset_percentage)); - for window in sorted.windows(2) { - let [start, end] = window else { continue }; - if pos >= (start.offset_percentage / 100.0) && pos <= (end.offset_percentage / 100.0) { - return (start, end); - } - } - - panic!("No keyframes available."); - } - - let (keyframe_start, keyframe_end) = find_keyframe_pair(pos, animation); - - let mut style = Style::default(); - let mut start_map = HashMap::new(); - let mut end_map = HashMap::new(); - - for prop in &keyframe_start.properties { - start_map.insert(std::mem::discriminant(prop), prop); - } - - for prop in &keyframe_end.properties { - end_map.insert(std::mem::discriminant(prop), prop); - } - - for key in start_map.keys().chain(end_map.keys()).collect::>() { - let start_prop = start_map.get(key); - let end_prop = end_map.get(key); - - let start_percentage = keyframe_start.offset_percentage / 100.0; - let end_percentage = keyframe_end.offset_percentage / 100.0; - let local_t = (pos - start_percentage) / (end_percentage - start_percentage); - - let t = match &animation.timing_function { - TimingFunction::Linear => { - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#linear - let linear = FixedCubicBezier::new(0.0, 0.0, 1.0, 1.0); - linear.cubic_bez.eval(local_t as f64).y - } - TimingFunction::Ease => { - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease - let ease = FixedCubicBezier::new(0.25, 0.1, 0.25, 1.0); - ease.cubic_bez.eval(local_t as f64).y - } - TimingFunction::EaseIn => { - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-in - let ease_in = FixedCubicBezier::new(0.42, 0.0, 1.0, 1.0); - ease_in.cubic_bez.eval(local_t as f64).y - } - TimingFunction::EaseOut => { - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-out - let ease_out = FixedCubicBezier::new(0.0, 0.0, 0.58, 1.0); - ease_out.cubic_bez.eval(local_t as f64).y - } - TimingFunction::EaseInOut => { - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#ease-in-out - let ease_in_out = FixedCubicBezier::new(0.42, 0.0, 0.58, 1.0); - ease_in_out.cubic_bez.eval(local_t as f64).y - } - // https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#cubic-beziernumber_01_number_number_01_number - TimingFunction::BezierCurve(cubic_bezier) => { - cubic_bezier.cubic_bez.eval(local_t as f64).y - } - }; - - fn lerp(a: f32, b: f32, t: f32) -> f32 { - a + (b - a) * t - } - - #[inline(always)] - fn resolve_unit(start: Unit, end: Unit, t: f64, set_prop: &mut dyn FnMut(Unit)) { - let resolved_start = match start { - Unit::Px(px) => px, - Unit::Percentage(percent) => percent, - Unit::Auto => panic!("Unit must not be auto.") - }; - - let resolved_end = match end { - Unit::Px(px) => px, - Unit::Percentage(percent) => percent, - Unit::Auto => panic!("Unit must not be auto.") - }; - let new = lerp(resolved_start, resolved_end, t as f32); - - // Naively asserts that start and end must be the same Unit type. - let new = match start { - Unit::Px(_) => Unit::Px(new), - Unit::Percentage(_) => Unit::Percentage(new), - _ => unreachable!() - }; - - set_prop(new); - } - - match (start_prop, end_prop) { - (Some(StyleProperty::Background(start)), Some(StyleProperty::Background(end))) => { - let new_color = start.lerp_rect(*end, t as f32); - style.set_background(new_color); - } - (Some(StyleProperty::Color(start)), Some(StyleProperty::Color(end))) => { - let new_color = start.lerp_rect(*end, t as f32); - style.set_color(new_color); - animation_flags.set_needs_relayout(true); - } - (Some(StyleProperty::FontSize(start)), Some(StyleProperty::FontSize(end))) => { - let new = lerp(*start, *end, t as f32); - style.set_font_size(new); - animation_flags.set_needs_relayout(true); - } - (Some(StyleProperty::Width(start)), Some(StyleProperty::Width(end))) - => { - resolve_unit(*start, *end, t, &mut |new| { - style.set_width(new); - }); - animation_flags.set_needs_relayout(true); - } - (Some(StyleProperty::Height(start)), Some(StyleProperty::Height(end))) => { - resolve_unit(*start, *end, t, &mut |new| { - style.set_height(new); - }); - animation_flags.set_needs_relayout(true); - } - - (Some(StyleProperty::Inset(start)), Some(StyleProperty::Inset(end))) => { - let trlb = zip(start.to_array(), end.to_array()).map(|(start, end)| { - let mut inset_unit = Unit::Auto; - resolve_unit(start, end, t, &mut |new| { - inset_unit = new; - }); - - inset_unit - }).collect::>(); - - let inset = TrblRectangle::new(trlb[0], trlb[1], trlb[2], trlb[3]); - - style.set_inset(inset); - animation_flags.set_needs_relayout(true); - } - - _ => {} - } - - } - - - - style - } -} \ No newline at end of file diff --git a/crates/craft_retained/src/animations/mod.rs b/crates/craft_retained/src/animations/mod.rs deleted file mode 100644 index 8e10d763..00000000 --- a/crates/craft_retained/src/animations/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod animation; - -pub use animation::Animation; -pub use animation::KeyFrame; -pub use animation::LoopAmount; -pub use animation::TimingFunction; \ No newline at end of file diff --git a/crates/craft_retained/src/app.rs b/crates/craft_retained/src/app.rs index df175867..5a1f1dc8 100644 --- a/crates/craft_retained/src/app.rs +++ b/crates/craft_retained/src/app.rs @@ -1,120 +1,71 @@ -use crate::elements::ElementIdMap; -use crate::events::EventDispatcher; -use crate::events::internal::InternalMessage; -use crate::events::{CraftMessage}; -use crate::layout::layout_context::measure_content; -use crate::style::{Display, Unit, Wrap}; -use crate::text::text_context::TextContext; -use crate::{RendererBox, WindowContext}; -use craft_logging::{info, span, Level}; -use craft_primitives::geometry::Rectangle; -use craft_resource_manager::{ResourceIdentifier, ResourceManager}; -use craft_runtime::CraftRuntimeHandle; -use kurbo::{Affine, Point}; -use peniko::Color; -use std::cell::{Cell}; use std::cell::RefCell; -use std::collections::{VecDeque}; +use std::collections::VecDeque; use std::ops::DerefMut; use std::rc::{Rc, Weak}; use std::sync::Arc; + #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] -use { - crate::accessibility::access_handler::CraftAccessHandler, - crate::accessibility::activation_handler::CraftActivationHandler, - crate::accessibility::deactivation_handler::CraftDeactivationHandler, -}; -#[cfg(feature = "accesskit")] -use { - accesskit::{Role, TreeUpdate}, - accesskit_winit::Adapter, -}; - -#[cfg(not(target_arch = "wasm32"))] -use std::time; -#[cfg(target_arch = "wasm32")] -use web_time as time; - -use crate::animations::animation::AnimationFlags; -use crate::document::DocumentManager; -use crate::elements::Element; -use crate::layout::layout_context::LayoutContext; -use craft_renderer::RenderList; +use accesskit::TreeUpdate; + +use craft_logging::info; + +use craft_primitives::geometry::{Point, Size}; + use craft_resource_manager::resource_event::ResourceEvent; use craft_resource_manager::resource_type::ResourceType; -use craft_runtime::Sender; -use std::time::Duration; -use taffy::{AvailableSpace, NodeId, TaffyTree}; -use ui_events::keyboard::{KeyboardEvent, Modifiers, NamedKey}; +use craft_resource_manager::{ResourceId, ResourceManager}; + +use craft_runtime::{CraftRuntimeHandle, Sender}; + +use taffy::NodeId; + +use ui_events::keyboard::KeyboardEvent; use ui_events::pointer::{PointerButtonEvent, PointerScrollEvent, PointerUpdate}; -use ui_events::ScrollDelta; -use ui_events::ScrollDelta::PixelDelta; -use winit::dpi::{LogicalSize, PhysicalSize}; -use winit::event::Ime; + +use winit::event::{Ime, WindowEvent}; use winit::event_loop::ActiveEventLoop; -use winit::window::{Window, WindowId}; +use winit::window::WindowId; + +use crate::CraftOptions; +use crate::elements::{ElementIdMap, ElementInternals, Window}; +use crate::events::internal::InternalMessage; +use crate::events::{Event, EventDispatcher, EventKind}; +use crate::layout::TaffyTree; +use crate::text::text_context::TextContext; +use crate::window_manager::WindowManager; thread_local! { - /// The most recently recorded window id. This is set every time a windows event occurs. - pub static CURRENT_WINDOW_ID : Cell> = const { Cell::new(None) }; - /// Records document-level state (focus, pointer captures, etc.) for internal use. - pub static DOCUMENTS: RefCell = RefCell::new(DocumentManager::new()); pub(crate) static ELEMENTS: RefCell = RefCell::new(ElementIdMap::new()); - pub(crate) static TAFFY_TREE: RefCell> = RefCell::new(TaffyTree::new()); - pub(crate) static PENDING_RESOURCES: RefCell> = RefCell::new(VecDeque::new()); - pub(crate) static IN_PROGRESS_RESOURCES: RefCell> = RefCell::new(VecDeque::new()); - pub(crate) static FOCUS: RefCell>>> = RefCell::new(None); + pub(crate) static PENDING_RESOURCES: RefCell> = const { RefCell::new(VecDeque::new()) }; + pub(crate) static IN_PROGRESS_RESOURCES: RefCell> = const { RefCell::new(VecDeque::new()) }; + pub(crate) static FOCUS: RefCell>>> = RefCell::new(None); + pub(crate) static WINDOW_MANAGER: RefCell = RefCell::new(WindowManager::new()); + pub(crate) static TAFFY_TREE: RefCell = RefCell::new(TaffyTree::new()); + /// An event queue that users or elements can manipulate. Cleared at the start and end of every event dispatch. + static EVENT_DISPATCH_QUEUE: RefCell> = RefCell::new(VecDeque::with_capacity(10)); + /// An event queue for capturing window events not generated by winit. + static WINDOW_EVENT_DISPATCH_QUEUE: RefCell> = RefCell::new(VecDeque::with_capacity(10)); } pub struct App { pub(crate) event_dispatcher: EventDispatcher, - pub(crate) root: Rc>, - /// A winit window. This is only valid between resume and pause. - pub window: Option>, /// The text context is used to manage fonts and text rendering. It is only valid between resume and pause. pub(crate) text_context: Option, - /// The renderer is used to draw the view. It is only valid between resume and pause. - pub renderer: Option, pub(crate) reload_fonts: bool, /// The resource manager is used to manage resources such as images and fonts. /// /// The resource manager is responsible for loading, caching, and providing access to resources. pub(crate) resource_manager: Arc, - // The user's reactive tree. - /// Provides a way for the user to get and set common window properties during view and update. - pub window_context: WindowContext, pub(crate) app_sender: Sender, - #[cfg(feature = "accesskit")] - pub(crate) accesskit_adapter: Option, - #[allow(dead_code)] pub(crate) runtime: CraftRuntimeHandle, - pub(crate) modifiers: Modifiers, - pub(crate) last_frame_time: time::Instant, - pub redraw_flags: RedrawFlags, - - pub(crate) render_list: RenderList, - pub(super) target_scratch: Vec>>, - - pub(crate) previous_animation_flags: AnimationFlags, + pub(super) target_scratch: Vec>>, #[allow(dead_code)] - pub(crate) focus: Option>>, -} - -#[derive(Debug)] -pub struct RedrawFlags { - rebuild_layout: bool, -} + pub(crate) craft_options: CraftOptions, -impl RedrawFlags { - pub fn new(rebuild_layout: bool) -> Self { - Self { rebuild_layout } - } - - pub fn should_rebuild_layout(&self) -> bool { - self.rebuild_layout - } + /// True if the winit app is active. + pub(crate) active: bool, } impl App { @@ -122,547 +73,243 @@ impl App { info!("Craft application is closing."); } - pub fn on_scale_factor_changed(&mut self, scale_factor: f64) { - self.window_context.scale_factor = scale_factor; - self.on_resize(self.window.as_ref().unwrap().inner_size()); + pub fn on_scale_factor_changed(&mut self, window: Window, scale_factor: f64) { + window.on_scale_factor_changed(scale_factor); } - pub fn on_process_user_events(&mut self) {} - - #[allow(unused_variables)] - pub fn on_resume(&mut self, window: Arc, renderer: RendererBox, event_loop: &ActiveEventLoop) { - window.set_ime_allowed(true); - + pub fn on_resume(&mut self, event_loop: &ActiveEventLoop) { + self.active = true; self.setup_text_context(); - self.renderer = Some(renderer); - - self.window = Some(window.clone()); - #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] - let action_handler = CraftAccessHandler { - runtime_handle: self.runtime.clone(), - app_sender: self.app_sender.clone(), - }; - #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] - let deactivation_handler = CraftDeactivationHandler::new(); - - let scale_factor = window.scale_factor(); - - self.window = Some(window.clone()); - self.window_context.scale_factor = scale_factor; - self.on_resize(window.inner_size()); - let tree_update = self.on_request_redraw(); - - #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] - let craft_activation_handler = CraftActivationHandler::new(tree_update); - - #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] - { - self.accesskit_adapter = Some(Adapter::with_direct_handlers( - event_loop, - &window, - craft_activation_handler, - #[cfg(feature = "accesskit")] - action_handler, - deactivation_handler, - )); - } - - window.set_visible(true); + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + window_manager.on_resume(self, event_loop); + }); } - /// Handles the window resize event. - pub fn on_resize(&mut self, new_size: PhysicalSize) { - self.window_context.window_size = new_size; - if let Some(renderer) = self.renderer.as_mut() { - renderer.resize_surface(new_size.width.max(1) as f32, new_size.height.max(1) as f32); - } - // On macOS the window needs to be redrawn manually after resizing - #[cfg(target_os = "macos")] - { - self.window.as_ref().unwrap().request_redraw(); + pub fn on_about_to_wait(&mut self, event_loop: &ActiveEventLoop) { + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + window_manager.on_about_to_wait(self, event_loop); + }); + + // TODO: Allow on wasm + #[cfg(not(target_arch = "wasm32"))] + if let Some(callback) = self.craft_options.craft_callback.take() { + let future = callback.call(); + self.runtime.spawn_current_thread(future); } } - /// Initialize any data needed to layout/render text. - fn setup_text_context(&mut self) { - if self.text_context.is_none() { - #[cfg(any(target_arch = "wasm32", not(feature = "system_fonts")))] - let mut text_context = TextContext::new(); - #[cfg(all(not(target_arch = "wasm32"), feature = "system_fonts"))] - let text_context = TextContext::new(); - - #[cfg(any(target_arch = "wasm32", not(feature = "system_fonts")))] - { - let regular = include_bytes!("../../../fonts/Roboto-Regular.ttf"); - let bold = include_bytes!("../../../fonts/Roboto-Bold.ttf"); - let semi_bold = include_bytes!("../../../fonts/Roboto-SemiBold.ttf"); - let medium = include_bytes!("../../../fonts/Roboto-Medium.ttf"); - - fn register_and_append(font_data: &'static [u8], text_context: &mut TextContext) { - let blob = peniko::Blob::new(Arc::new(font_data)); - let fonts = text_context.font_context.collection.register_fonts(blob, None); - - // Register all the Roboto families under parley::GenericFamily::SystemUi. - // This will become the fallback font for platforms like WASM. - text_context - .font_context - .collection - .append_generic_families(parley::GenericFamily::SystemUi, fonts.iter().map(|f| f.0)); - } - - register_and_append(regular, &mut text_context); - register_and_append(bold, &mut text_context); - register_and_append(semi_bold, &mut text_context); - register_and_append(medium, &mut text_context); - } - - self.text_context = Some(text_context); - } + pub fn on_suspended(&mut self, _event_loop: &ActiveEventLoop) { + self.active = false; } - /// Updates the view by applying the latest changes to the reactive tree. - pub(crate) fn update_view(&mut self) {} + /// Handles the window resize event. + pub fn on_resize(&mut self, window: Window, new_size: Size) { + window.on_resize(new_size); + } /// Updates the reactive tree, layouts the elements, and draws the view. - #[cfg(feature = "accesskit")] - pub fn on_request_redraw(&mut self) -> Option { - self.on_request_redraw_internal(); - self.window.as_ref()?; - let window = self.window.as_mut().unwrap().clone(); - - let tree_update = self.compute_accessibility_tree(); - if let Some(accesskit_adapter) = &mut self.accesskit_adapter { + #[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] + pub fn on_request_redraw(&mut self, window: Window) -> Option { + self.on_request_redraw_internal(window.clone()); + + let tree_update = window.compute_accessibility_tree_window(); + if let Some(accesskit_adapter) = &mut window.inner.borrow_mut().accesskit_adapter { accesskit_adapter.update_if_active(|| tree_update); - window.pre_present_notify(); None } else { - window.pre_present_notify(); Some(tree_update) } } /// Updates the reactive tree, layouts the elements, and draws the view. - #[cfg(not(feature = "accesskit"))] - pub fn on_request_redraw(&mut self) { - self.on_request_redraw_internal(); + #[cfg(any(not(feature = "accesskit"), target_arch = "wasm32"))] + pub fn on_request_redraw(&mut self, window: Window) { + self.on_request_redraw_internal(window); } - //#[cfg(not(feature = "accesskit"))] + pub fn on_move(&mut self, _window: Window) {} - fn on_request_redraw_internal(&mut self) { - if self.window.is_none() { + pub fn on_pointer_scroll(&mut self, window: Window, pointer_scroll_update: PointerScrollEvent) { + if window.inner.borrow_mut().maybe_zoom(&pointer_scroll_update) { return; } - - self.update_resources(); - - let now = time::Instant::now(); - let delta_time = now - self.last_frame_time; - self.last_frame_time = now; - - let surface_size = self.window_context.window_size(); - - self.update_view(); - - let root_size = surface_size; - - if self.renderer.is_some() { - self.renderer.as_mut().unwrap().surface_set_clear_color(Color::WHITE); - } - - let layout_origin = Point::new(0.0, 0.0); - - { - if self.redraw_flags.should_rebuild_layout() { - self.layout_tree( - root_size, - layout_origin, - self.window_context.effective_scale_factor(), - self.window_context.mouse_position, - ); - } - - self.animate_tree(&delta_time, layout_origin, root_size); - - if self.renderer.is_some() { - self.draw_reactive_tree(self.window_context.mouse_position); - } - } - - { - let span = span!(Level::INFO, "renderer_submit"); - let _enter = span.enter(); - - if self.renderer.is_some() { - self.renderer.as_mut().unwrap().submit(self.resource_manager.clone()); - } - } - - if let Some(window) = &self.window { - self.window_context.apply_requests(window); - self.window_context.reset(); - } - - self.on_process_user_events(); - - self.view_introspection(); + self.dispatch_event(window, &EventKind::PointerScroll(pointer_scroll_update)); } - pub fn on_pointer_scroll(&mut self, pointer_scroll_update: PointerScrollEvent) { - if self.modifiers.ctrl() && pointer_scroll_update.pointer.pointer_type == ui_events::pointer::PointerType::Mouse - { - let y: f32 = match pointer_scroll_update.delta { - ScrollDelta::PageDelta(_, y) => y, - ScrollDelta::LineDelta(_, y) => y, - PixelDelta(physical) => physical.y as f32, - }; - if y < 0.0 { - self.window_context.zoom_out(); - } else { - self.window_context.zoom_in(); - } - self.request_redraw(RedrawFlags::new(true)); - return; - } - - let event = CraftMessage::PointerScroll(pointer_scroll_update); - let message = event; - - self.dispatch_event(&message, false); - self.request_redraw(RedrawFlags::new(true)); - } - - pub fn on_pointer_button(&mut self, pointer_event: PointerButtonEvent, is_up: bool) { - let mut pointer_event = pointer_event; - let zoom = self.window_context.zoom_factor; - pointer_event.state.position.x /= zoom; - pointer_event.state.position.y /= zoom; - - let cursor_position = pointer_event.state.position; + pub fn on_pointer_button(&mut self, window: Window, pointer_event: PointerButtonEvent, is_up: bool) { + let cursor_position = pointer_event.state.logical_point(); let event = if is_up { - CraftMessage::PointerButtonUp(pointer_event) + EventKind::PointerButtonUp(pointer_event) } else { - CraftMessage::PointerButtonDown(pointer_event) + EventKind::PointerButtonDown(pointer_event) }; - let message = event; - self.window_context.mouse_position = Some(Point::new(cursor_position.x, cursor_position.y)); + window.set_mouse_position(Some(Point::new(cursor_position.x, cursor_position.y))); - self.dispatch_event(&message, true); - - self.request_redraw(RedrawFlags::new(true)); + self.dispatch_event(window.clone(), &event); } - pub fn on_pointer_moved(&mut self, mouse_moved: PointerUpdate) { - let mut mouse_moved = mouse_moved; - let zoom = self.window_context.zoom_factor; - mouse_moved.current.position.x /= zoom; - mouse_moved.current.position.y /= zoom; - - self.window_context.mouse_position = Some(mouse_moved.current.logical_point()); - - let message = CraftMessage::PointerMovedEvent(mouse_moved); - - self.dispatch_event(&message, true); - - self.request_redraw(RedrawFlags::new(true)); + pub fn on_pointer_moved(&mut self, window: Window, mouse_moved: PointerUpdate) { + window.set_mouse_position(Some(mouse_moved.current.logical_point())); + self.dispatch_event(window.clone(), &EventKind::PointerMovedEvent(mouse_moved)); } - pub fn on_ime(&mut self, ime: Ime) { - let event = CraftMessage::ImeEvent(ime); - let message = event; - - self.dispatch_event(&message, false); - - self.request_redraw(RedrawFlags::new(true)); + pub fn on_ime(&mut self, window: Window, ime: Ime) { + self.dispatch_event(window.clone(), &EventKind::ImeEvent(ime)); } - /// Dispatch messages to the reactive tree. - fn dispatch_event(&mut self, message: &CraftMessage, _is_style: bool) { - self.event_dispatcher.dispatch_event( - message, - self.window_context.mouse_position, - self.root.clone(), - &mut self.text_context, - &mut self.render_list, - &mut self.target_scratch - ); - self.window.clone().unwrap().request_redraw(); - } - - pub fn on_keyboard_input(&mut self, keyboard_input: KeyboardEvent) { - self.modifiers = keyboard_input.modifiers; - if keyboard_input.key == ui_events::keyboard::Key::Named(NamedKey::Control) && keyboard_input.state.is_up() { - self.modifiers.set(Modifiers::CONTROL, false); - } - if keyboard_input.modifiers.ctrl() { - if keyboard_input.key == ui_events::keyboard::Key::Character("=".to_string()) { - self.window_context.zoom_in(); - self.request_redraw(RedrawFlags::new(true)); - return; - } else if keyboard_input.key == ui_events::keyboard::Key::Character("-".to_string()) { - self.window_context.zoom_out(); - self.request_redraw(RedrawFlags::new(true)); - return; - } + pub fn on_keyboard_input(&mut self, window: Window, keyboard_input: KeyboardEvent) { + window.inner.borrow_mut().update_modifiers(&keyboard_input); + if window.inner.borrow_mut().maybe_zoom_keyboard(&keyboard_input) { + return; } - - let keyboard_event = CraftMessage::KeyboardInputEvent(keyboard_input.clone()); - let message = keyboard_event; - - self.dispatch_event(&message, false); - - self.request_redraw(RedrawFlags::new(true)); + self.dispatch_event(window.clone(), &EventKind::KeyboardInputEvent(keyboard_input)); } pub fn on_resource_event(&mut self, resource_event: ResourceEvent) { match resource_event { - ResourceEvent::Loaded(resource_identifier, resource_type, resource) => { + ResourceEvent::Loaded(resource_id, resource_type, resource) => { IN_PROGRESS_RESOURCES.with_borrow_mut(|in_progress| { - in_progress.retain_mut(|(resource, _resource_type)| *resource != resource_identifier); + in_progress.retain_mut(|(resource, _resource_type)| *resource != resource_id); }); if let Some(_text_context) = self.text_context.as_mut() && resource_type == ResourceType::Font && resource.data().is_some() { // Todo: Load the font into the text context. - self.resource_manager.insert(resource_identifier.clone(), Arc::new(resource)); + self.resource_manager.insert(resource_id.clone(), Arc::new(resource)); self.reload_fonts = true; } else if resource_type == ResourceType::Image || resource_type == ResourceType::TinyVg { - self.resource_manager.insert(resource_identifier, Arc::new(resource)); + self.resource_manager.insert(resource_id, Arc::new(resource)); } + // TODO: Only mark dirty affected nodes. + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + window_manager.dirty_and_redraw_all_windows(self); + }); } ResourceEvent::UnLoaded(_) => {} } } - fn view_introspection(&mut self) {} - - fn request_redraw(&mut self, redraw_flags: RedrawFlags) { - self.redraw_flags = redraw_flags; - if let Some(window) = &self.window { - window.request_redraw(); - } - } - - /// "Animates" a tree by calling `on_animation_frame` and changing an element's styles. - fn animate_tree(&mut self, delta_time: &Duration, layout_origin: Point, viewport_size: LogicalSize) { - let span = span!(Level::INFO, "animate_tree"); - let _enter = span.enter(); - - let old_has_active_animation = self.previous_animation_flags.has_active_animation(); - let root_element = self.root.clone(); - - // Damage track across recursive calls to `on_animation_frame`. - let mut animation_flags = AnimationFlags::default(); - root_element.borrow_mut().on_animation_frame(&mut animation_flags, *delta_time); - self.previous_animation_flags = animation_flags; - - // Perform a relayout if an animation used any layout effecting style property. - if animation_flags.needs_relayout() || old_has_active_animation { - root_element.borrow_mut().reset_layout_item(); - - self.layout_tree( - viewport_size, - layout_origin, - self.window_context.effective_scale_factor(), - self.window_context.mouse_position, - ); - } - - // Request a redraw if there is at least one animation playing. - // ControlFlow::Poll is set in `about_to_wait`. - if animation_flags.has_active_animation() || old_has_active_animation { - // Winit does not guarantee when a redraw event will happen, but that should be fine, at worst we redraw an extra time. - self.request_redraw(RedrawFlags::new(old_has_active_animation)); - } - } - - #[allow(clippy::too_many_arguments)] - fn layout_tree( - &mut self, - viewport_size: LogicalSize, - origin: Point, - scale_factor: f64, - mouse_position: Option, - ) { - let root_element = self.root.clone(); - style_root_element(root_element.borrow_mut().deref_mut(), viewport_size); - let text_context = self.text_context.as_mut().unwrap(); - - { - let span = span!(Level::INFO, "layout"); - let _enter = span.enter(); - TAFFY_TREE.with_borrow_mut(|taffy_tree| { - layout( - taffy_tree, - root_element, - viewport_size, - text_context, - origin, - self.resource_manager.clone(), - scale_factor, - mouse_position, - ) - }); - }; - } - - #[allow(clippy::too_many_arguments)] - fn draw_reactive_tree(&mut self, mouse_position: Option) { - let text_context = self.text_context.as_mut().unwrap(); - { - let span = span!(Level::INFO, "render"); - let _enter = span.enter(); - self.render_list.clear(); - let scale_factor = self.window_context.effective_scale_factor(); - - let renderer = self.renderer.as_mut().unwrap(); - - { - let span = span!(Level::INFO, "render(element)"); - let _enter = span.enter(); - self.root.borrow_mut().draw(&mut self.render_list, text_context, mouse_position, scale_factor); - } - - renderer.sort_and_cull_render_list(&mut self.render_list); - - let window = Rectangle { - x: 0.0, - y: 0.0, - width: renderer.surface_width(), - height: renderer.surface_height(), - }; - renderer.prepare_render_list(&mut self.render_list, self.resource_manager.clone(), window); - } + fn on_request_redraw_internal(&mut self, window: Window) { + self.update_resources(); + window.on_redraw(self.text_context.as_mut().unwrap(), self.resource_manager.clone()); } - #[cfg(feature = "accesskit")] - fn compute_accessibility_tree(&mut self) -> TreeUpdate { - let tree = accesskit::Tree { - root: accesskit::NodeId(0), - toolkit_name: Some("Craft".to_string()), - toolkit_version: None, - }; - - let focus_id = self.focus.clone().map(|node| node.upgrade().unwrap().borrow().id()).unwrap_or(0); - let mut tree_update = TreeUpdate { - nodes: vec![], - tree: Some(tree), - focus: accesskit::NodeId(focus_id), - }; - - self.root.borrow_mut().compute_accessibility_tree( - &mut tree_update, - None, - self.window_context.effective_scale_factor(), + fn dispatch_event(&mut self, window: Window, message: &EventKind) { + let mouse_pos = window.mouse_position(); + let render_list = window.inner.borrow().render_list.clone(); + self.event_dispatcher.dispatch_event( + message, + mouse_pos, + window.inner.clone(), + &mut self.text_context, + render_list.borrow_mut().deref_mut(), + &mut self.target_scratch, ); - tree_update.nodes[0].1.set_role(Role::Window); - - tree_update + window.winit_window().unwrap().request_redraw(); } fn update_resources(&mut self) { PENDING_RESOURCES.with_borrow_mut(|pending_resources| { IN_PROGRESS_RESOURCES.with_borrow_mut(|in_progress| { for (resource, resource_type) in pending_resources.drain(..) { - if self.resource_manager.contains(&resource) || in_progress.contains(&(resource.clone(), resource_type)) { + if self.resource_manager.contains(&resource) + || in_progress.contains(&(resource.clone(), resource_type)) + { continue; } - self.resource_manager.async_download_resource_and_send_message_on_finish(self.app_sender.clone(), resource.clone(), resource_type); + self.resource_manager + .async_download_resource_and_send_message_on_finish( + self.app_sender.clone(), + resource.clone(), + resource_type, + ); in_progress.push_back((resource, resource_type)); } }); }); } -} -fn style_root_element(root: &mut dyn Element, root_size: LogicalSize) { - let is_user_root_height_auto = { - let root_children = root.children(); - root_children[0].borrow().style().height().is_auto() - }; + /// Initialize any data needed to layout/render text. + fn setup_text_context(&mut self) { + if self.text_context.is_none() { + #[cfg(any(target_arch = "wasm32", not(feature = "system_fonts")))] + let mut text_context = TextContext::new(); + #[cfg(all(not(target_arch = "wasm32"), feature = "system_fonts"))] + let text_context = TextContext::new(); + + #[cfg(any(target_arch = "wasm32", not(feature = "system_fonts")))] + { + let regular = include_bytes!("../../../fonts/Roboto-Regular.ttf"); + let bold = include_bytes!("../../../fonts/Roboto-Bold.ttf"); + let semi_bold = include_bytes!("../../../fonts/Roboto-SemiBold.ttf"); + let medium = include_bytes!("../../../fonts/Roboto-Medium.ttf"); + + fn register_and_append(font_data: &'static [u8], text_context: &mut TextContext) { + let blob = peniko::Blob::new(Arc::new(font_data)); + let fonts = text_context.font_context.collection.register_fonts(blob, None); - let style = root.style_mut(); + // Register all the Roboto families under parley::GenericFamily::SystemUi. + // This will become the fallback font for platforms like WASM. + text_context + .font_context + .collection + .append_generic_families(parley::GenericFamily::SystemUi, fonts.iter().map(|f| f.0)); + } - style.set_width(Unit::Px(root_size.width)); - style.set_wrap(Wrap::Wrap); - style.set_display(Display::Block); + register_and_append(regular, &mut text_context); + register_and_append(bold, &mut text_context); + register_and_append(semi_bold, &mut text_context); + register_and_append(medium, &mut text_context); + } - if is_user_root_height_auto { - style.set_height(Unit::Auto); - } else { - style.set_height(Unit::Px(root_size.height)); + self.text_context = Some(text_context); + } } } -#[allow(clippy::too_many_arguments)] -fn layout( - taffy_tree: &mut TaffyTree, - root_element: Rc>, - window_size: LogicalSize, - text_context: &mut TextContext, - origin: Point, - resource_manager: Arc, - scale_factor: f64, - pointer: Option, -) -> NodeId { - let root_node = { - let span = span!(Level::INFO, "compute layout(internal)"); - let _enter = span.enter(); - root_element.borrow_mut().compute_layout(taffy_tree, scale_factor); - // There should usually be a layout node. If not, exiting early could also make sense. - root_element.borrow() - .element_data() - .layout_item - .taffy_node_id - .expect("A root element must have a layout node.") - }; - - let available_space: taffy::Size = taffy::Size { - width: AvailableSpace::Definite(window_size.width), - height: AvailableSpace::Definite(window_size.height), - }; - - { - let span = span!(Level::INFO, "layout(taffy)"); - let _enter = span.enter(); - taffy_tree - .compute_layout_with_measure( - root_node, - available_space, - |known_dimensions, available_space, _node_id, node_context, style| { - measure_content( - known_dimensions, - available_space, - node_context, - text_context, - resource_manager.clone(), - style, - ) - }, - ) - .unwrap(); - } +/// Enqueues an event at the back of the dispatch queue. +/// +/// This does **not** invoke any element `on_event` handlers. +/// Only user-registered event callbacks will be dispatched. +pub fn queue_event(event: Event, message: EventKind) { + EVENT_DISPATCH_QUEUE.with_borrow_mut(|event_queue| { + event_queue.push_back((event, message)); + }); +} - let transform = Affine::IDENTITY; - - let mut layout_order: u32 = 0; - { - let span = span!(Level::INFO, "layout(apply)"); - let _enter = span.enter(); - root_element.borrow_mut().apply_layout( - taffy_tree, - origin, - &mut layout_order, - transform, - pointer, - text_context, - None, - scale_factor, - ); - } +/// Pops from the front of the event dispatch queue and returns the result. +pub(crate) fn dequeue_event() -> Option<(Event, EventKind)> { + EVENT_DISPATCH_QUEUE.with_borrow_mut(|event_queue| event_queue.pop_front()) +} + +/// Enqueues an event at the back of the dispatch queue. +/// +/// This does **not** invoke any element `on_event` handlers. +/// Only user-registered event callbacks will be dispatched. +pub fn queue_window_event(window_id: WindowId, event: WindowEvent) { + WINDOW_EVENT_DISPATCH_QUEUE.with_borrow_mut(|event_queue| { + event_queue.push_back((window_id, event)); + }); +} + +/// Pops from the front of the event dispatch queue and returns the result. +pub(crate) fn dequeue_window_event() -> Option<(WindowId, WindowEvent)> { + WINDOW_EVENT_DISPATCH_QUEUE.with_borrow_mut(|event_queue| event_queue.pop_front()) +} + +#[inline] +pub fn request_layout(taffy_node: NodeId) { + TAFFY_TREE.with_borrow_mut(|taffy_tree| { + taffy_tree.mark_dirty(taffy_node); + }); +} - root_node +#[inline] +pub fn request_apply_layout(node: NodeId) { + TAFFY_TREE.with_borrow_mut(|taffy_tree| { + taffy_tree.request_apply_layout(node); + }); } diff --git a/crates/craft_retained/src/craft_winit_state.rs b/crates/craft_retained/src/craft_winit_state.rs index 1915bcc5..42314fc2 100644 --- a/crates/craft_retained/src/craft_winit_state.rs +++ b/crates/craft_retained/src/craft_winit_state.rs @@ -1,40 +1,33 @@ -#[cfg(target_arch = "wasm32")] -use { - wasm_bindgen::JsCast, - winit::platform::web::WindowAttributesExtWebSys, -}; +//! Integration with the winit event loop. -#[cfg(target_arch = "wasm32")] -use {crate::wasm_queue::WasmQueue, crate::wasm_queue::WASM_QUEUE}; +#[cfg(not(target_arch = "wasm32"))] +use std::time; -use crate::events::internal::InternalMessage; -use craft_renderer::renderer::Renderer; -use crate::{CraftOptions}; use craft_logging::info; +use craft_primitives::geometry::Size; + +use craft_runtime::{CraftRuntimeHandle, Receiver, Sender, pop_gui_thread_work}; + +use ui_events::pointer::PointerEvent; + +use ui_events_winit::{WindowEventReducer, WindowEventTranslation}; + +#[cfg(target_arch = "wasm32")] +use web_time as time; use winit::application::ApplicationHandler; use winit::event::{StartCause, WindowEvent}; use winit::event_loop::{ActiveEventLoop, ControlFlow}; -use winit::window::WindowAttributes; -use winit::window::{Window, WindowId}; +use winit::window::WindowId; -#[cfg(not(target_arch = "wasm32"))] -use std::time; +use crate::CraftOptions; +use crate::app::{App, WINDOW_MANAGER, dequeue_window_event}; +use crate::elements::Window; +use crate::events::internal::InternalMessage; #[cfg(target_arch = "wasm32")] -use web_time as time; - -use craft_runtime::Receiver; -use craft_runtime::Sender; -use craft_runtime::CraftRuntimeHandle; +use {crate::wasm_queue::WASM_QUEUE, crate::wasm_queue::WasmQueue}; -use crate::app::{App, CURRENT_WINDOW_ID, DOCUMENTS}; -use std::sync::Arc; -use ui_events::pointer::{PointerEvent}; -use ui_events_winit::{WindowEventReducer, WindowEventTranslation}; -use winit::dpi::LogicalSize; -use crate::document::Document; - -const WAIT_TIME: time::Duration = time::Duration::from_millis(15); +const WAIT_TIME: time::Duration = time::Duration::from_millis(10); /// Stores state related to Winit. /// @@ -57,89 +50,27 @@ pub(crate) struct CraftWinitState { craft_state: CraftState, } -impl CraftWinitState { - pub(crate) fn new(craft_state: CraftState) -> Self { - Self { - craft_state, - } - } -} - impl ApplicationHandler for CraftWinitState { fn new_events(&mut self, _event_loop: &ActiveEventLoop, cause: StartCause) { self.craft_state.wait_cancelled = matches!(cause, StartCause::WaitCancelled { .. }) } fn resumed(&mut self, event_loop: &ActiveEventLoop) { - let craft_state = &mut self.craft_state; - - let mut window_attributes = - WindowAttributes::default().with_title(craft_state.craft_options.window_title.as_str()).with_visible(false); - - if let Some(window_size) = &craft_state.craft_options.window_size { - window_attributes = - window_attributes.with_inner_size(LogicalSize::new(window_size.width, window_size.height)); - } - - #[cfg(target_arch = "wasm32")] - let window_attributes = { - let canvas = web_sys::window() - .unwrap() - .document() - .unwrap() - .get_element_by_id("canvas") - .unwrap() - .dyn_into::() - .unwrap(); - - window_attributes.with_canvas(Some(canvas)) - }; - - let window: Arc = - Arc::from(event_loop.create_window(window_attributes).expect("Failed to create window.")); - info!("Created window"); - - //craft_state.event_reducer.set_scale_factor(&window); - - let renderer_type = craft_state.craft_options.renderer; - let window_copy = window.clone(); - - cfg_if::cfg_if! { - if #[cfg(not(target_arch = "wasm32"))] { - let renderer = craft_state.runtime.borrow_tokio_runtime().block_on(async { - let renderer: Box = renderer_type.create(window_copy).await; - renderer - }); - craft_state.craft_app.on_resume(window, renderer, event_loop); - } else { - let app_sender = craft_state.app_sender.clone(); - let window_copy_2 = window_copy.clone(); - craft_state.runtime.spawn(async move { - let renderer: Box = renderer_type.create(window_copy).await; - app_sender - .send(InternalMessage::RendererCreated(window_copy_2, renderer)) - .await - .expect("Failed to send RendererCreated message"); - }); - } - } + self.craft_state.craft_app.on_resume(event_loop); } fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { - let craft_state = &mut self.craft_state; + let window: Option = + WINDOW_MANAGER.with_borrow_mut(|window_manager| window_manager.get_window_by_id(window_id)); - CURRENT_WINDOW_ID.set(Some(window_id)); - // Create a new document if there is none for the current window. - DOCUMENTS.with_borrow_mut(|docs| { - if docs.get_document_by_window_id(window_id).is_none() { - docs.add_document(window_id, Document::new()); - } - }); + let window = if let Some(window) = window { window } else { return }; + + let craft_state = &mut self.craft_state; - #[cfg(feature = "accesskit")] + /*#[cfg(all(feature = "accesskit", not(target_arch = "wasm32")))] if let Some(accesskit_adapter) = &mut craft_state.craft_app.accesskit_adapter { accesskit_adapter.process_event(craft_state.craft_app.window.as_ref().unwrap(), &event); - } + }*/ if !matches!( event, @@ -148,34 +79,41 @@ impl ApplicationHandler for CraftWinitState { .. } ) { - match craft_state.event_reducer.reduce(1.0, &event) { + match craft_state + .event_reducer + .reduce(window.effective_scale_factor(), &event) + { Some(WindowEventTranslation::Keyboard(keyboard_event)) => { use ui_events::keyboard::{Key, NamedKey}; if keyboard_event.state.is_down() && matches!(keyboard_event.key, Key::Named(NamedKey::Escape)) { event_loop.exit(); } else { - craft_state.craft_app.on_keyboard_input(keyboard_event); + craft_state.craft_app.on_keyboard_input(window, keyboard_event); } return; } Some(WindowEventTranslation::Pointer(pointer_event)) => { match pointer_event { PointerEvent::Down(pointer_button_update) => { - craft_state.craft_app.on_pointer_button(pointer_button_update, false); + craft_state + .craft_app + .on_pointer_button(window, pointer_button_update, false); } PointerEvent::Up(pointer_button_update) => { - craft_state.craft_app.on_pointer_button(pointer_button_update, true); + craft_state + .craft_app + .on_pointer_button(window, pointer_button_update, true); } PointerEvent::Move(pointer_update) => { - craft_state.craft_app.on_pointer_moved(pointer_update); + craft_state.craft_app.on_pointer_moved(window, pointer_update); } PointerEvent::Cancel(_) => {} PointerEvent::Enter(_) => {} PointerEvent::Leave(_) => {} PointerEvent::Scroll(pointer_scroll_update) => { - craft_state.craft_app.on_pointer_scroll(pointer_scroll_update); - }, - PointerEvent::Gesture(_) => todo!() + craft_state.craft_app.on_pointer_scroll(window, pointer_scroll_update); + } + PointerEvent::Gesture(_) => todo!(), } return; } @@ -185,20 +123,26 @@ impl ApplicationHandler for CraftWinitState { match event { WindowEvent::CloseRequested => { - craft_state.close_requested = true; - craft_state.craft_app.on_close_requested(); + self.on_close_requested(&window); } WindowEvent::ScaleFactorChanged { scale_factor, .. } => { - craft_state.craft_app.on_scale_factor_changed(scale_factor); + craft_state.craft_app.on_scale_factor_changed(window, scale_factor); } WindowEvent::Resized(new_size) => { - craft_state.craft_app.on_resize(new_size); + let new_size = Size:: { + width: new_size.width as f32, + height: new_size.height as f32, + }; + craft_state.craft_app.on_resize(window, new_size); } WindowEvent::Ime(ime) => { - craft_state.craft_app.on_ime(ime); + craft_state.craft_app.on_ime(window, ime); } WindowEvent::RedrawRequested => { - craft_state.craft_app.on_request_redraw(); + craft_state.craft_app.on_request_redraw(window); + } + WindowEvent::Moved(_) => { + craft_state.craft_app.on_move(window); } _ => (), } @@ -208,62 +152,101 @@ impl ApplicationHandler for CraftWinitState { if event_loop.exiting() { return; } + self.craft_state.runtime.update_local_set(); + self.process_non_winit_window_events(event_loop); + self.process_craft_messages(); + self.process_external_work(); + self.craft_state.craft_app.on_about_to_wait(event_loop); + self.maybe_exit(event_loop); + event_loop.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME)); + } - let craft_state = &mut self.craft_state; + fn suspended(&mut self, event_loop: &ActiveEventLoop) { + self.craft_state.craft_app.on_suspended(event_loop); + } +} - cfg_if::cfg_if! { - if #[cfg(not(target_arch = "wasm32"))] { - craft_state.runtime.borrow_tokio_runtime().block_on(async { - while let Ok(message) = craft_state.winit_receiver.try_recv() { - match message { - InternalMessage::ResourceEvent(resource_event) => { - craft_state.craft_app.on_resource_event(resource_event); - } - #[cfg(target_arch = "wasm32")] - InternalMessage::RendererCreated(window, renderer) => { - craft_state.craft_app.on_resume(window, renderer); - } - } +impl CraftWinitState { + pub(crate) fn new(craft_state: CraftState) -> Self { + Self { craft_state } + } + + #[cfg(not(target_arch = "wasm32"))] + fn process_craft_messages(&mut self) { + self.craft_state.runtime.borrow_tokio_runtime().block_on(async { + while let Ok(message) = self.craft_state.winit_receiver.try_recv() { + match message { + InternalMessage::ResourceEvent(resource_event) => { + self.craft_state.craft_app.on_resource_event(resource_event); } - }); - } else { - WASM_QUEUE.with_borrow_mut(|wasm_queue: &mut WasmQueue| { - wasm_queue.drain(|message| { - match message { - InternalMessage::ResourceEvent(resource_event) => { - craft_state.craft_app.on_resource_event(resource_event); - } - #[cfg(target_arch = "wasm32")] - InternalMessage::RendererCreated(window, renderer) => { - craft_state.craft_app.on_resume(window, renderer, event_loop); - if let Some(window) = craft_state.craft_app.window.as_ref() { - window.request_redraw(); - } - } - } - }); - }); + #[cfg(target_arch = "wasm32")] + InternalMessage::RendererCreated(window, renderer) => {} + } } + }); + } + + #[cfg(target_arch = "wasm32")] + fn process_craft_messages(&mut self) { + WASM_QUEUE.with_borrow_mut(|wasm_queue: &mut WasmQueue| { + wasm_queue.drain(|message| match message { + InternalMessage::ResourceEvent(resource_event) => { + self.craft_state.craft_app.on_resource_event(resource_event); + } + #[cfg(target_arch = "wasm32")] + InternalMessage::RendererCreated(winit_window, renderer) => { + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + let window = window_manager.get_window_by_id(winit_window.id()); + window.clone().unwrap().inner.borrow_mut().renderer = Some(renderer); + let sz = Size::new( + winit_window.inner_size().width as f32, + winit_window.inner_size().height as f32, + ); + window.unwrap().on_resize(sz); + window_manager.redraw_all(&mut self.craft_state.craft_app); + }); + } + }); + }); + } + + fn process_external_work(&mut self) { + // Do work sent from other threads and update all the windows. + let mut work_done = false; + while let Some(work) = pop_gui_thread_work() { + work(); + work_done = true; } - if craft_state.close_requested { + if work_done { + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + window_manager.redraw_all(&mut self.craft_state.craft_app); + }); + } + } + + fn maybe_exit(&mut self, event_loop: &ActiveEventLoop) { + if self.craft_state.close_requested { info!("Exiting winit event loop"); event_loop.exit(); - return; } + } - // Switch to Poll mode if we are running animations. - - let has_active_animation = self.craft_state.craft_app.previous_animation_flags.has_active_animation(); - - if has_active_animation { - event_loop.set_control_flow(ControlFlow::Poll); - } else { - event_loop.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME)); + fn process_non_winit_window_events(&mut self, event_loop: &ActiveEventLoop) { + while let Some((window_id, event)) = dequeue_window_event() { + self.window_event(event_loop, window_id, event); } - event_loop.set_control_flow(ControlFlow::Poll); - + } + + fn on_close_requested(&mut self, window: &Window) { + WINDOW_MANAGER.with_borrow_mut(|window_manager| { + window_manager.close_window(window); + if window_manager.is_empty() { + self.craft_state.close_requested = true; + self.craft_state.craft_app.on_close_requested(); + } + }); } } diff --git a/crates/craft_retained/src/craftcallback.rs b/crates/craft_retained/src/craftcallback.rs new file mode 100644 index 00000000..bf2e6d29 --- /dev/null +++ b/crates/craft_retained/src/craftcallback.rs @@ -0,0 +1,35 @@ +use std::future::Future; +use std::pin::Pin; + +pub trait CloneableCraftFn: 'static { + fn call(&self) -> Pin>>; + fn clone_box(&self) -> Box; +} + +impl CloneableCraftFn for F +where + F: Fn() -> Fut + Clone + 'static, + Fut: Future + 'static, +{ + fn call(&self) -> Pin>> { + Box::pin((self)()) + } + + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } +} + +pub struct CraftCallback(pub Box); + +impl Clone for CraftCallback { + fn clone(&self) -> Self { + CraftCallback(self.0.clone_box()) + } +} + +impl CraftCallback { + pub fn call(&self) -> Pin>> { + self.0.call() + } +} diff --git a/crates/craft_retained/src/document/core.rs b/crates/craft_retained/src/document/core.rs deleted file mode 100644 index 7506831a..00000000 --- a/crates/craft_retained/src/document/core.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Weak; -use ui_events::pointer::PointerId; -use crate::elements::Element; - -/// Stores window specific information like pointer captures, focus (soon), etc. -pub struct Document { - /// Tracks elements that are *currently* pointer captured. - pub(crate) pointer_captures: HashMap>>, - /// Tracks elements that *should* be pointer captured. - pub(crate) pending_pointer_captures: HashMap>>, -} - -impl Default for Document { - fn default() -> Self { - Self::new() - } -} - -impl Document { - pub fn new() -> Self { - Self { - pointer_captures: Default::default(), - pending_pointer_captures: Default::default(), - } - } -} \ No newline at end of file diff --git a/crates/craft_retained/src/document/document_manager.rs b/crates/craft_retained/src/document/document_manager.rs deleted file mode 100644 index 6edae241..00000000 --- a/crates/craft_retained/src/document/document_manager.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::collections::HashMap; -use winit::window::WindowId; -use crate::app::{CURRENT_WINDOW_ID}; -use crate::document::Document; - -/// A wrapper to get a document with a window id or the current document. -pub struct DocumentManager { - documents: HashMap, -} - -impl DocumentManager { - pub(crate) fn new() -> Self { - Self { - documents: HashMap::new(), - } - } - - pub(crate) fn add_document(&mut self, window_id: WindowId, document: Document) { - self.documents.insert(window_id, document); - } - - pub fn get_current_document(&mut self) -> &mut Document { - let window_id_key = &CURRENT_WINDOW_ID.get().unwrap(); - self.documents.get_mut(window_id_key).unwrap() - } - pub fn get_document_by_window_id(&mut self, window_id: WindowId) -> Option<&mut Document> { - self.documents.get_mut(&window_id) - } -} \ No newline at end of file diff --git a/crates/craft_retained/src/document/mod.rs b/crates/craft_retained/src/document/mod.rs deleted file mode 100644 index 249cec00..00000000 --- a/crates/craft_retained/src/document/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod core; -pub mod document_manager; - -pub use document_manager::DocumentManager; -pub use core::Document; \ No newline at end of file diff --git a/crates/craft_retained/src/elements/container.rs b/crates/craft_retained/src/elements/container.rs index 93164d55..ebf218c1 100644 --- a/crates/craft_retained/src/elements/container.rs +++ b/crates/craft_retained/src/elements/container.rs @@ -1,55 +1,55 @@ //! Stores one or more elements. -use crate::app::{ELEMENTS, TAFFY_TREE}; -use crate::elements::core::{resolve_clip_for_scrollable, ElementInternals}; -use crate::elements::element_data::ElementData; -use crate::elements::{scrollable, Element}; -use crate::events::{CraftMessage, Event}; -use crate::layout::layout_context::LayoutContext; -use crate::text::text_context::TextContext; -use craft_primitives::geometry::Rectangle; -use craft_renderer::RenderList; -use kurbo::{Affine, Point}; use std::any::Any; use std::cell::RefCell; -use std::ops::Deref; use std::rc::{Rc, Weak}; -use taffy::TaffyTree; + +use craft_primitives::geometry::{Affine, Point, Rectangle}; +use craft_renderer::RenderList; + +use crate::elements::element_data::ElementData; +use crate::elements::internal_helpers::{apply_generic_container_layout, draw_generic_container, push_child_to_element}; +use crate::elements::traits::DeepClone; +use crate::elements::{AsElement, Element, ElementInternals, resolve_clip_for_scrollable, scrollable}; +use crate::events::{Event, EventKind}; +use crate::layout::TaffyTree; +use crate::style::Overflow; +use crate::text::text_context::TextContext; + +#[derive(Clone)] +pub struct Container { + pub inner: Rc>, +} /// Stores one or more elements. /// /// If overflow is set to scroll, it will become scrollable. -pub struct Container { +#[derive(Clone)] +pub struct ContainerInner { element_data: ElementData, - me: Option>>, } -impl Container { - pub fn new() -> Rc> { - let me = Rc::new(RefCell::new(Self { - element_data: ElementData::new(true), - me: None, - })); - - TAFFY_TREE.with_borrow_mut(|taffy_tree| { - let node_id = taffy_tree.new_leaf(me.borrow().style().to_taffy_style()).expect("TODO: panic message"); - me.borrow_mut().element_data.layout_item.taffy_node_id = Some(node_id); - }); - - let me_element: Rc> = me.clone(); +impl Default for Container { + fn default() -> Self { + Self::new() + } +} - me.borrow_mut().me = Some(Rc::downgrade(&me.clone())); - me.borrow_mut().element_data.me = Some(Rc::downgrade(&me_element)); +impl Element for Container {} - ELEMENTS.with_borrow_mut(|elements| { - elements.insert(me.borrow().deref()); - }); +impl Drop for ContainerInner { + fn drop(&mut self) { + ElementInternals::drop(self) + } +} - me +impl AsElement for Container { + fn as_element_rc(&self) -> Rc> { + self.inner.clone() } } -impl crate::elements::core::ElementData for Container { +impl crate::elements::ElementData for ContainerInner { fn element_data(&self) -> &ElementData { &self.element_data } @@ -59,134 +59,77 @@ impl crate::elements::core::ElementData for Container { } } -impl Element for Container { - fn push(&mut self, child: Rc>) -> &mut Self - where - Self: Sized, - { - let me: Weak> = self.me.clone().unwrap() as Weak>; - child.borrow_mut().element_data_mut().parent = Some(me); - self.element_data.children.push(child.clone()); - - // Add the children's taffy node. - TAFFY_TREE.with_borrow_mut(|taffy_tree| { - let parent_id = self.element_data.layout_item.taffy_node_id.unwrap(); - let child_id = child.borrow().element_data().layout_item.taffy_node_id; - if let Some(child_id) = child_id { - taffy_tree.add_child(parent_id, child_id).unwrap(); - - taffy_tree.mark_dirty(parent_id).expect("Failed to mark taffy node dirty"); - } - }); - - self - } - - fn push_dyn(&mut self, child: Rc>) { - self.push(child); - } - - /// Appends multiple typed children in one call - fn extend(&mut self, children: impl IntoIterator>>) -> &mut Self - where - Self: Sized, - { - let me: Weak> = self.me.clone().unwrap() as Weak>; - let children: Vec<_> = children.into_iter().collect(); - - for child in &children { - child.borrow_mut().element_data_mut().parent = Some(me.clone()); - } - - self.element_data.children.extend(children.iter().cloned()); - - // Add the children's taffy node. - TAFFY_TREE.with_borrow_mut(|taffy_tree| { - let parent_id = self.element_data.layout_item.taffy_node_id.unwrap(); - for child in &children { - if let Some(child_id) = child.borrow().element_data().layout_item.taffy_node_id { - taffy_tree.add_child(parent_id, child_id).unwrap(); - } - } - taffy_tree.mark_dirty(parent_id).expect("Failed to mark taffy node dirty"); - }); - - self - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -impl ElementInternals for Container { - fn compute_layout(&mut self, taffy_tree: &mut TaffyTree, scale_factor: f64) { - self.compute_layout_children(taffy_tree, scale_factor); - - self.apply_style_to_layout_node_if_dirty(taffy_tree); +impl ElementInternals for ContainerInner { + fn deep_clone(&self) -> Rc> { + self.deep_clone_internal() } fn apply_layout( &mut self, - taffy_tree: &mut TaffyTree, + taffy_tree: &mut TaffyTree, position: Point, z_index: &mut u32, transform: Affine, - pointer: Option, text_context: &mut TextContext, clip_bounds: Option, scale_factor: f64, ) { - let layout = taffy_tree.layout(self.element_data.layout_item.taffy_node_id.unwrap()).unwrap(); - self.resolve_box(position, transform, layout, z_index); - self.apply_borders(scale_factor); - - self.element_data.apply_scroll(layout); - self.apply_clip(clip_bounds); - - let scroll_y = self.element_data.scroll().map_or(0.0, |s| s.scroll_y() as f64); - let child_transform = Affine::translate((0.0, -scroll_y)); - - self.apply_layout_children(taffy_tree, z_index, transform * child_transform, pointer, text_context, scale_factor) + apply_generic_container_layout( + self, + taffy_tree, + position, + z_index, + transform, + text_context, + clip_bounds, + scale_factor, + ); } - fn draw( - &mut self, - renderer: &mut RenderList, - text_context: &mut TextContext, - pointer: Option, - scale_factor: f64, - ) { - if !self.is_visible() { - return; - } - self.add_hit_testable(renderer, true, scale_factor); - - // We draw the borders before we start any layers, so that we don't clip the borders. - self.draw_borders(renderer, scale_factor); - - self.maybe_start_layer(renderer, scale_factor); - self.draw_children(renderer, text_context, pointer, scale_factor); - self.maybe_end_layer(renderer); - - self.draw_scrollbar(renderer, scale_factor); + fn draw(&mut self, renderer: &mut RenderList, text_context: &mut TextContext, scale_factor: f64) { + draw_generic_container(self, renderer, text_context, scale_factor); } fn on_event( &mut self, - message: &CraftMessage, + message: &EventKind, _text_context: &mut TextContext, event: &mut Event, _target: Option>>, ) { - scrollable::on_scroll_events(self, message, event); + scrollable::handle_scroll_logic(self, message, event); } fn apply_clip(&mut self, clip_bounds: Option) { - resolve_clip_for_scrollable(self, clip_bounds); + let overflow = self.style().get_overflow(); + if overflow[0] == Overflow::Scroll || overflow[1] == Overflow::Scroll { + resolve_clip_for_scrollable(self, clip_bounds); + } else { + self.element_data.layout.resolve_clip(clip_bounds); + } + } + + fn push(&mut self, child: Rc>) { + push_child_to_element(self, child); + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + +impl Container { + pub fn new() -> Self { + let inner = Rc::new_cyclic(|me: &Weak>| { + RefCell::new(ContainerInner { + element_data: ElementData::new(me.clone(), true), + }) + }); + inner.borrow_mut().element_data.create_layout_node(None); + Self { inner } } } diff --git a/crates/craft_retained/src/elements/core/element_internals.rs b/crates/craft_retained/src/elements/core/element_internals.rs deleted file mode 100644 index a669cbd8..00000000 --- a/crates/craft_retained/src/elements/core/element_internals.rs +++ /dev/null @@ -1,388 +0,0 @@ -use crate::animations::animation::{ActiveAnimation, AnimationFlags, AnimationStatus}; -use crate::events::{CraftMessage, Event}; -use crate::layout::layout_context::LayoutContext; -use crate::layout::layout_item::{draw_borders_generic, CssComputedBorder, LayoutItem}; -use crate::style::{Display, Style}; -use crate::text::text_context::TextContext; -use craft_primitives::geometry::{ElementBox, Rectangle}; -use craft_renderer::RenderList; -use kurbo::{Affine, Point, Vec2}; -use rustc_hash::FxHashMap; -use std::cell::RefCell; -use std::rc::Rc; -use std::time::Duration; -use taffy::{Overflow, TaffyTree}; - -use crate::elements::core::element_data::ElementData; -use crate::elements::Element; -#[cfg(feature = "accesskit")] -use accesskit::{Action, Role}; -use craft_primitives::geometry::borders::CssRoundedRect; - -/// Internal element methods that should typically be ignored by users. Public for custom elements. -pub trait ElementInternals: ElementData { - /// Compute the element's layout. - fn compute_layout(&mut self, taffy_tree: &mut TaffyTree, scale_factor: f64); - - /// A helper to compute the layout for all children. - fn compute_layout_children(&mut self, taffy_tree: &mut TaffyTree, scale_factor: f64) { - for child in &self.element_data().children { - child.borrow_mut().compute_layout(taffy_tree, scale_factor); - } - } - - /// A helper to apply the layout for all children. - fn apply_layout_children( - &mut self, - taffy_tree: &mut TaffyTree, - z_index: &mut u32, - transform: Affine, - pointer: Option, - text_context: &mut TextContext, - scale_factor: f64, - ) { - for child in &self.element_data().children { - child.borrow_mut().apply_layout( - taffy_tree, - self.element_data().layout_item.computed_box.position, - z_index, - transform, - pointer, - text_context, - self.element_data().layout_item.clip_bounds, - scale_factor, - ); - } - } - - /// A helper to check if the element is visible. - fn is_visible(&self) -> bool { - let style = &self.element_data().style; - style.visible() && style.display() != Display::None - } - - /// A helper to draw all children. - fn draw_children( - &mut self, - renderer: &mut RenderList, - text_context: &mut TextContext, - pointer: Option, - scale_factor: f64, - ) { - for child in self.children() { - child.borrow_mut().draw(renderer, text_context, pointer, scale_factor); - } - } - - /// A helper to re-apply the style to the layout node when dirty. - fn apply_style_to_layout_node_if_dirty(&mut self, taffy_tree: &mut TaffyTree) { - let element_data = self.element_data_mut(); - if element_data.style.is_dirty { - let node_id = element_data.layout_item.taffy_node_id.unwrap(); - let style: taffy::Style = element_data.style.to_taffy_style(); - taffy_tree.set_style(node_id, style).expect("Failed to set style on node."); - element_data.style.is_dirty = false; - } - } - - /// Applies the layout results from the [`TaffyTree`]. - /// This method retrieves the computed layout for `root_node` and updates the - /// element’s internal state accordingly. It resolves the element's position, - /// transform, clipping, borders, and stacking order, producing the final - /// layout state used for rendering. - /// - /// # Parameters - /// - `taffy_tree`: The layout tree containing the computed results. - /// - `root_node`: The node whose layout information should be applied. - /// - `position`: The absolute position of the element within its parent context. - /// - `z_index`: A mutable counter used to assign stacking order as elements - /// are processed. - /// - `transform`: The accumulated transform to apply to this element. - /// - `pointer`: The current pointer position, if available, for hit-testing. - /// - `text_context`: Context used for text layout and measurement. - /// - `clip_bounds`: Optional clipping rectangle inherited from ancestors. - /// - /// # Effects - /// This function mutates internal element state to reflect the final resolved - /// layout and may trigger updates such as clipping regions, border geometry, - /// and z-index assignment. - #[allow(clippy::too_many_arguments)] - fn apply_layout( - &mut self, - taffy_tree: &mut TaffyTree, - position: Point, - z_index: &mut u32, - transform: Affine, - pointer: Option, - text_context: &mut TextContext, - clip_bounds: Option, - scale_factor: f64, - ); - - /// Draws the element and its visual contents. - /// - /// Implementations should use the provided [`RenderList`] to issue - /// drawing commands. - /// - /// - `renderer`: the active render list to draw into. - /// - `text_context`: text shaping and layout context. - /// - `pointer`: optional pointer position for hover effects. - /// - `window`: optional window handle. - /// - `scale_factor`: scale factor. - fn draw( - &mut self, - _renderer: &mut RenderList, - _text_context: &mut TextContext, - _pointer: Option, - _scale_factor: f64, - ) { - } - - /// Computes a [`TreeUpdate`] reflecting any accessibility changes. - #[cfg(feature = "accesskit")] - fn compute_accessibility_tree( - &mut self, - tree: &mut accesskit::TreeUpdate, - parent_index: Option, - scale_factor: f64, - ) { - let current_node_id = accesskit::NodeId(self.element_data().internal_id); - - let mut current_node = accesskit::Node::new(Role::GenericContainer); - if !self.element_data().on_pointer_button_up.is_empty() { - current_node.set_role(Role::Button); - current_node.add_action(Action::Click); - } - - let padding_box = - self.element_data().layout_item.computed_box_transformed.padding_rectangle().scale(scale_factor); - - current_node.set_bounds(accesskit::Rect { - x0: padding_box.left() as f64, - y0: padding_box.top() as f64, - x1: padding_box.right() as f64, - y1: padding_box.bottom() as f64, - }); - - let current_index = tree.nodes.len(); // The current node is the last one added. - - if let Some(parent_index) = parent_index { - let parent_node = tree.nodes.get_mut(parent_index).unwrap(); - parent_node.1.push_child(current_node_id); - } - - tree.nodes.push((current_node_id, current_node)); - - for child in self.element_data_mut().children.iter_mut() { - child.borrow_mut().compute_accessibility_tree(tree, Some(current_index), scale_factor); - } - } - - /// Handles default events. - fn on_event( - &mut self, - _message: &CraftMessage, - _text_context: &mut TextContext, - _event: &mut Event, - _target: Option>>, - ) { - } - - /// Computes this element's box model. - fn resolve_box( - &mut self, - relative_position: Point, - scroll_transform: Affine, - result: &taffy::Layout, - layout_order: &mut u32, - ) { - let position = self.element_data().style.position(); - self.element_data_mut().layout_item.resolve_box( - relative_position, - scroll_transform, - result, - layout_order, - position, - ); - } - - /// Computes this element's clip box. - fn apply_clip(&mut self, clip_bounds: Option) { - self.element_data_mut().layout_item.resolve_clip(clip_bounds); - } - - fn apply_borders(&mut self, scale_factor: f64) { - let current_style = self.element_data().current_style(); - let has_border = current_style.has_border(); - let border_radius = current_style.border_radius(); - let border_color = ¤t_style.border_color(); - - self.element_data_mut().layout_item.apply_borders(has_border, border_radius, scale_factor, border_color); - } - - /// Called after layout, and is responsible for updating the animation state of an element. - fn on_animation_frame(&mut self, animation_flags: &mut AnimationFlags, delta_time: Duration) { - let base_state = self.element_data_mut(); - - // If we don't have an animation in the current style then try to fall back to the normal style. - let current_style = if let Some(current_style) = base_state.current_style_mut_no_fallback() { - current_style - } else { - &mut base_state.style - }; - - // This is pretty hacky, but we can avoid allocating a hashmap for every element. - let active_animations = { - if base_state.animations.is_none() { - base_state.animations = Some(FxHashMap::default()); - } - - base_state.animations.as_mut().unwrap() - }; - - let current_style_animations = &mut current_style.animations; - for ani in &mut *current_style_animations { - if !active_animations.contains_key(&ani.name) { - active_animations.insert( - ani.name.clone(), - ActiveAnimation { - current: Duration::ZERO, - status: AnimationStatus::Playing, - loop_amount: ani.loop_amount, - }, - ); - } - } - - active_animations.retain(|key, _| current_style_animations.iter().any(|ani| &ani.name == key)); - - active_animations.retain(|anim_name, active_animation| { - if active_animation.status == AnimationStatus::Playing { - animation_flags.set_has_active_animation(true); - } - - if let Some(animation) = current_style.animation(anim_name) { - active_animation.tick(animation_flags, animation, delta_time); - let new_style = active_animation.compute_style(current_style, animation, animation_flags); - *current_style = Style::merge(current_style, &new_style); - true - } else { - false - } - }); - - for child in self.children() { - child.borrow_mut().on_animation_frame(animation_flags, delta_time); - } - } - - /// A bit of a hack to reset the layout item of an element recursively. - fn reset_layout_item(&mut self) { - self.element_data_mut().layout_item = LayoutItem::default(); - - for child in self.element_data_mut().children.iter_mut() { - child.borrow_mut().reset_layout_item(); - } - } - - fn add_hit_testable(&mut self, renderer: &mut RenderList, hit_testable: bool, scale_factor: f64) { - /*let ed = self.element_data().borrow(); - let has_events = - !ed.on_pointer_button_up.is_empty() || - !ed.on_pointer_moved.is_empty() || - !ed.on_keyboard_input.is_empty() || - !ed.on_pointer_button_down.is_empty() || - !ed.on_got_pointer_capture.is_empty() || - !ed.on_pointer_enter.is_empty() || - !ed.on_pointer_leave.is_empty() || - !ed.on_lost_pointer_capture;*/ - if hit_testable { - let id = self.element_data().internal_id; - renderer.push_hit_testable(id, self.element_data().layout_item.computed_box_transformed.padding_rectangle().scale(scale_factor)); - } - } - - fn draw_borders(&self, renderer: &mut RenderList, scale_factor: f64) { - let current_style = self.element_data().current_style(); - - self.element_data().layout_item.draw_borders(renderer, current_style, scale_factor); - } - - fn maybe_start_layer(&self, renderer: &mut RenderList, scale_factor: f64) { - let element_data = self.element_data(); - let padding_rectangle = - element_data.layout_item.computed_box_transformed.padding_rectangle().scale(scale_factor); - - if self.should_start_new_layer() { - renderer.push_layer(padding_rectangle); - } - } - - fn maybe_end_layer(&self, renderer: &mut RenderList) { - if self.should_start_new_layer() { - renderer.pop_layer(); - } - } - - fn draw_scrollbar(&mut self, renderer: &mut RenderList, scale_factor: f64) { - if !self.element_data().is_scrollable() { - return; - } - - let border_color = self.element_data().current_style().border_color(); - let scrollbar_color = self.element_data().current_style().scrollbar_color(); - let scrollbar_thumb_radius = self - .element_data() - .current_style() - .scrollbar_thumb_radius() - .map(|radii| Vec2::new(radii.0 as f64, radii.1 as f64)); - // let scrollbar_thumb_radius = self.element_data().current_style(). - let track_rect = self.element_data_mut().layout_item.computed_scroll_track.scale(scale_factor); - let thumb_rect = self.element_data_mut().layout_item.computed_scroll_thumb.scale(scale_factor); - - let border_spec = CssRoundedRect::new(thumb_rect.to_kurbo(), [0.0, 0.0, 0.0, 0.0], scrollbar_thumb_radius); - let mut computed_border_spec = CssComputedBorder::new(border_spec); - computed_border_spec.scale(scale_factor); - - renderer.draw_rect(track_rect, scrollbar_color.track_color); - draw_borders_generic( - renderer, - &computed_border_spec, - border_color.to_array(), - scrollbar_color.thumb_color, - ); - } - - fn should_start_new_layer(&self) -> bool { - let element_data = self.element_data(); - - element_data.current_style().overflow()[1] == Overflow::Scroll - } - - /// Returns the element's [`ElementBox`] without any transforms applied. - fn computed_box(&self) -> ElementBox { - self.element_data().layout_item.computed_box - } - - /// Gets - fn get_default_style() -> Style - where - Self: Sized, - { - Style::default() - } -} - -pub(crate) fn resolve_clip_for_scrollable(element: &mut dyn Element, clip_bounds: Option) { - let element_data = element.element_data_mut(); - if element_data.is_scrollable() { - let scroll_clip_bounds = element_data.layout_item.computed_box_transformed.padding_rectangle(); - if let Some(clip_bounds) = clip_bounds { - element_data.layout_item.clip_bounds = scroll_clip_bounds.intersection(&clip_bounds); - } else { - element_data.layout_item.clip_bounds = Some(scroll_clip_bounds); - } - } else { - element_data.layout_item.clip_bounds = clip_bounds; - } -} diff --git a/crates/craft_retained/src/elements/core/mod.rs b/crates/craft_retained/src/elements/core/mod.rs deleted file mode 100644 index 5892c0bf..00000000 --- a/crates/craft_retained/src/elements/core/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod element_internals; -mod element_data; - -/// Note: this could be hidden behind a custom elements feature. -pub use element_internals::ElementInternals; -pub(crate) use element_internals::resolve_clip_for_scrollable; -pub use element_data::ElementData; \ No newline at end of file diff --git a/crates/craft_retained/src/elements/dropdown.rs b/crates/craft_retained/src/elements/dropdown.rs new file mode 100644 index 00000000..84a35ce5 --- /dev/null +++ b/crates/craft_retained/src/elements/dropdown.rs @@ -0,0 +1,703 @@ +//! An element to select a single item from a collapsable vertical list of options. + +use std::any::Any; +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +use craft_primitives::geometry::{BezPath, Rectangle, TrblRectangle}; + +use craft_renderer::{Brush, RenderList}; + +use craft_primitives::geometry::{Affine, Point, Vec2}; + +use peniko::Color; + +use ui_events::pointer::PointerId; + +use crate::app::{TAFFY_TREE, queue_event, request_apply_layout}; +use crate::elements::element_data::ElementData as ElementDataStruct; +use crate::elements::scrollable::{apply_scroll_layout, draw_scrollbar, handle_scroll_logic_advance}; +use crate::elements::traits::DeepClone; +use crate::elements::{AsElement, Element, ElementData, ElementInternals, resolve_clip_for_scrollable}; +use crate::events::{Event, EventKind}; +use crate::layout::TaffyTree; +use crate::layout::layout::Layout; +use crate::style::{AlignItems, BoxShadow, Display, FlexDirection, Overflow, Position, Style, Unit}; +use crate::text::text_context::TextContext; +use crate::{auto, px, rgba}; + +/// An element to select a single item from a collapsable vertical list of options. +/// +/// # Example +/// +/// ```no_run +/// use craft_retained::elements::{Dropdown, Element, Text, Window}; +/// use craft_retained::{CraftOptions, craft_main, px}; +/// +/// fn main() { +/// Window::new("Dropdown").push( +/// Dropdown::new() +/// .width(px(100)) +/// .push(Text::new("Item 1").font_size(20.0).selectable(false)) +/// .push(Text::new("Item 2").font_size(20.0).selectable(false)) +/// .push(Text::new("Item 3").font_size(20.0).selectable(false)) +/// .selected_item(0), +/// ); +/// craft_main(CraftOptions::basic("Dropdown")); +/// } +/// ``` +#[derive(Clone)] +pub struct Dropdown { + pub inner: Rc>, +} + +#[derive(Clone)] +pub struct Shape { + pub layout: Layout, + pub style: Box + + + + + + + + \ No newline at end of file diff --git a/website/src/docs.rs b/website/src/docs.rs new file mode 100644 index 00000000..d23db73f --- /dev/null +++ b/website/src/docs.rs @@ -0,0 +1,19 @@ +use craft_retained::elements::{Container, Element}; +use craft_retained::pct; +use craft_retained::style::{Display, FlexDirection, Overflow, Unit}; + +use crate::router::NavigateFn; + +pub(crate) fn docs(_navigate_fn: NavigateFn) -> Container { + Container::new() + .width(pct(100)) + .overflow(Overflow::Visible, Overflow::Scroll) + .push( + Container::new() + .display(Display::Flex) + .width(pct(100)) + .margin(Unit::Px(0.0), Unit::Auto, Unit::Px(0.0), Unit::Auto) + .flex_direction(FlexDirection::Column) + .flex_grow(1.0), + ) +} diff --git a/website/src/examples.rs b/website/src/examples.rs new file mode 100644 index 00000000..7cab0c18 --- /dev/null +++ b/website/src/examples.rs @@ -0,0 +1,196 @@ +#[allow(dead_code)] +#[path = "../../examples/counter_retained/main.rs"] +pub mod counter_retained; + +#[allow(dead_code)] +#[path = "../../examples/text/main.rs"] +mod text; + +#[allow(dead_code)] +#[path = "../../examples/pointer_events/main.rs"] +mod pointer_events; + +use std::cell::RefCell; +use std::rc::Rc; + +use craft_retained::elements::{Container, Element, Text}; +use craft_retained::events::ui_events::pointer::PointerButton; +use craft_retained::style::Display::Flex; +use craft_retained::style::{FlexDirection, FontWeight, Overflow, Unit}; +use craft_retained::{palette, pct, px}; + +use crate::WebsiteGlobalState; +use crate::examples::counter_retained::counter; +use crate::examples::pointer_events::pointer_events; +use crate::examples::text::text; +use crate::router::NavigateFn; +use crate::theme::{ACTIVE_LINK_COLOR, DEFAULT_LINK_COLOR, WRAPPER_PADDING_LEFT, WRAPPER_PADDING_RIGHT, wrapper}; + +const COUNTER_EXAMPLE_LINK: &str = "/examples/counter"; +const POINTER_EVENTS_EXAMPLE_LINK: &str = "/examples/pointer-events"; +const TEXT_EXAMPLE_LINK: &str = "/examples/text"; + +fn create_examples_link( + label: &str, + example_link: &str, + example_to_show: &str, + navigate_fn: NavigateFn, + example_container: Container, + examples: Vec, +) -> Text { + let example_link_captured = example_link.to_string(); + let mut text = Text::new(label) + .color(DEFAULT_LINK_COLOR) + .on_pointer_button_up(Rc::new(move |_event, pointer_button_event| { + if pointer_button_event.button == Some(PointerButton::Primary) { + update_active_example(example_link_captured.as_str(), example_container.clone(), &examples); + navigate_fn(example_link_captured.as_str()); + } + })) + .id(example_link) + .selectable(false); + if example_to_show == example_link { + text = text.color(ACTIVE_LINK_COLOR); + } + text +} + +fn examples_sidebar( + example_to_show: &str, + navigate_fn: NavigateFn, + example_container: Container, + examples: Vec, +) -> Container { + let mut links = vec![ + create_examples_link( + "Counter", + COUNTER_EXAMPLE_LINK, + example_to_show, + navigate_fn.clone(), + example_container.clone(), + examples.clone(), + ), + create_examples_link( + "Pointer Events", + POINTER_EVENTS_EXAMPLE_LINK, + example_to_show, + navigate_fn.clone(), + example_container.clone(), + examples.clone(), + ), + create_examples_link( + "Text", + TEXT_EXAMPLE_LINK, + example_to_show, + navigate_fn.clone(), + example_container.clone(), + examples.clone(), + ), + ]; + + if true + /*window.window_width() <= MOBILE_MEDIA_QUERY_WIDTH*/ + { + let container = Container::new() + .display(Flex) + .flex_direction(FlexDirection::Column) + .gap(px(12), px(12)) + .push( + Text::new("Examples") + .selectable(false) + .font_weight(FontWeight::MEDIUM) + .font_size(18.0), + ); + + let mut dropdown = Container::new() + .display(Flex) + .flex_direction(FlexDirection::Column) + .min_width(px(200)) + .width(px(200)) + .max_width(px(300)); + + for link in links.drain(..) { + let is_selected = link.get_id().map(|id| id == example_to_show).unwrap_or(false); + if is_selected { + //dropdown = dropdown.selected_item(index); + } + dropdown = dropdown.push(link); + } + + container.push(dropdown) + } else { + let mut container = Container::new() + .display(Flex) + .flex_direction(FlexDirection::Column) + .gap(px(15), px(15)) + .min_width(px(200)) + .padding(px(0), px(20), px(20), px(0)) + .height(pct(100)) + .push(Text::new("Examples").font_weight(FontWeight::MEDIUM).font_size(24.0)); + + for link in links.drain(..) { + container = container.push(link); + } + + container + } +} + +pub fn examples(context: Rc>, navigate_fn: NavigateFn) -> Container { + let route = context.borrow().get_route(); + + let examples = vec![ + counter().id(COUNTER_EXAMPLE_LINK), + pointer_events().id(POINTER_EVENTS_EXAMPLE_LINK), + text().id(TEXT_EXAMPLE_LINK), + ]; + + let container_height = 600.0; //(context.window().window_height() - NAVBAR_HEIGHT - vertical_padding * 2.0).max(0.0); + + let current_index = examples + .iter() + .position(|ex| ex.get_id().as_deref() == Some(route.as_str())) + .unwrap_or(0); + + let example_container = Container::new() + .width(pct(100)) + .height(px(container_height)) + .background_color(palette::css::WHITE) + .push(examples[current_index].clone()); + + let vertical_padding = 50.0; + let wrapper = wrapper() + .padding( + Unit::Px(vertical_padding), + WRAPPER_PADDING_RIGHT, + Unit::Px(vertical_padding), + WRAPPER_PADDING_LEFT, + ) + .push(examples_sidebar( + &route, + navigate_fn.clone(), + example_container.clone(), + examples.clone(), + )); + + /*if context.window().window_width() <= MOBILE_MEDIA_QUERY_WIDTH { + wrapper = wrapper.flex_direction(FlexDirection::Column); + wrapper = wrapper.gap(px(20), px(20)); + }*/ + + let wrapper = wrapper.push(example_container.clone()); + + Container::new() + .overflow(Overflow::Visible, Overflow::Scroll) + .push(wrapper) +} + +fn update_active_example(active: &str, example_container: Container, examples: &[Container]) { + for example in examples { + if example.get_id().unwrap() == active { + example_container.remove_all_children(); + example_container.push(example.clone()); + return; + } + } +} diff --git a/website/src/index.rs b/website/src/index.rs new file mode 100644 index 00000000..b71fb0d0 --- /dev/null +++ b/website/src/index.rs @@ -0,0 +1,174 @@ +use craft_retained::elements::{Container, Element, Text, TinyVg}; +use craft_retained::style::{AlignItems, Display, FlexDirection, FlexWrap, FontWeight, JustifyContent, Overflow, Unit}; +use craft_retained::{Color, ResourceId, palette, pct, px, rgb}; + +use crate::link::Link; +use crate::router::NavigateFn; +use crate::theme::{WRAPPER_PADDING_LEFT, WRAPPER_PADDING_RIGHT, wrapper}; +use crate::web_link::WebLink; + +fn hero_intro(navigate_fn: NavigateFn) -> Container { + let bg_wrapper = Container::new().width(pct(100)).background_color(rgb(45, 48, 53)); + + let inner_wrapper = wrapper() + .display(Display::Flex) + .flex_direction(FlexDirection::Column) + .padding( + Unit::Px(100.0), + WRAPPER_PADDING_RIGHT, + Unit::Px(100.0), + WRAPPER_PADDING_LEFT, + ); + + let inner_wrapper = inner_wrapper + .push( + Text::new("A Reactive GUI Framework for Rust") + .color(Color::WHITE) + /*.font_size(if window_ctx.inner_size().width <= MOBILE_MEDIA_QUERY_WIDTH { + 36.0 + } else { + 56.0 + })*/ + .font_size(56.0) + .line_height(1.0) + .max_width(px(680)) + .font_weight(FontWeight::BOLD) + .margin(px(0), px(0), px(32), px(0)), + ) + .push( + Text::new("Build your UI with regular Rust code.") + .line_height(1.0) + .color(Color::WHITE) + .font_size(20.0), + ); + + let github_button = Text::new("GitHub") + .selectable(false) + .display(Display::Flex) + .align_items(Some(AlignItems::Center)) + .justify_content(Some(JustifyContent::Center)) + .font_size(22.0) + .min_width(px(100)) + .border_width(px(1), px(1), px(1), px(1)) + .border_radius((8.0, 8.0), (8.0, 8.0), (8.0, 8.0), (8.0, 8.0)) + .padding(px(8), px(20), px(8), px(20)) + .border_color( + palette::css::WHITE, + palette::css::WHITE, + palette::css::WHITE, + palette::css::WHITE, + ) + .color(palette::css::WHITE); + + let craft_button = Text::new("Learn Craft") + .selectable(false) + .display(Display::Flex) + .align_items(Some(AlignItems::Center)) + .justify_content(Some(JustifyContent::Center)) + .font_size(22.0) + .min_width(px(100)) + .border_radius((8.0, 8.0), (8.0, 8.0), (8.0, 8.0), (8.0, 8.0)) + .padding(px(8), px(20), px(8), px(20)) + .background_color(rgb(69, 117, 230)) + .color(palette::css::WHITE); + + let buttons = Container::new() + .display(Display::Flex) + .wrap(FlexWrap::Wrap) + .gap(px(17), px(17)) + .margin(px(40), px(0), px(0), px(0)) + .push(Link(move || navigate_fn("/docs")).push(craft_button)) + .push(WebLink("https://github.com/craft-gui/craft").push(github_button)); + + let inner_wrapper = inner_wrapper.push(buttons); + + bg_wrapper.push(inner_wrapper) +} + +fn hero_features() -> Container { + fn hero_item(title: &str, text: &str, icon: ResourceId) -> Container { + let sub_title_color = Color::from_rgb8(70, 70, 70); + + let icon_title = Container::new().push(TinyVg::new(icon)).push( + Text::new(title) + .font_weight(FontWeight::MEDIUM) + .font_size(24.0) + .margin(px(0), px(0), px(0), px(10)), + ); + + Container::new() + .gap(px(10), px(10)) + .flex_grow(1.0) + .flex_shrink(1.0) + .min_width(px(320)) + .flex_basis(pct(50)) + .display(Display::Flex) + .flex_direction(FlexDirection::Column) + .push(icon_title) + .push(Text::new(text).font_size(18.0).color(sub_title_color)) + } + + Container::new() + .background_color(rgb(247, 247, 247)) + .width(pct(100)) + .push( + wrapper() + .padding(Unit::Px(100.0), WRAPPER_PADDING_LEFT, Unit::Px(100.0), WRAPPER_PADDING_RIGHT) + .display(Display::Flex) + .wrap(FlexWrap::Wrap) + .gap(px(0), px(50)) + .push(Text::new("Features").width(pct(100)).font_size(36.0).font_weight(FontWeight::SEMIBOLD)) + .push( + hero_item( + "Reactive", + "When your data changes, we automatically re-run your view function.", + ResourceId::Bytes(include_bytes!("../assets/electric_bolt_24dp_000000_FILL0_wght400_GRAD0_opsz24.tvg")) + ) + ) + .push( + hero_item( + "Components", + "Components are reusable blocks that manage their own state and define both how they are rendered and how they respond to updates.", + ResourceId::Bytes(include_bytes!("../assets/view_comfy_24dp_000000_FILL0_wght400_GRAD0_opsz24.tvg")) + ) + ) + .push( + hero_item( + "Pure Rust without macros", + "No macros.", + ResourceId::Bytes(include_bytes!("../assets/code_24dp_000000_FILL0_wght400_GRAD0_opsz24.tvg")) + ) + ) + .push( + hero_item( + "Web-like styling", + "We use Taffy, an implementation of the CSS flexbox, block, and grid layout algorithms, for simple and familiar styling.", + ResourceId::Bytes(include_bytes!("../assets/brush_24dp_000000_FILL0_wght400_GRAD0_opsz24.tvg")) + ) + ) + .push( + hero_item( + "Cross Platform", + "Currently we support Windows, macOS, Linux, Web, and Android.", + ResourceId::Bytes(include_bytes!("../assets/devices_24dp_000000_FILL0_wght400_GRAD0_opsz24.tvg")) + ) + ) + + ) +} + +pub(crate) fn index_page(navigate_fn: NavigateFn) -> Container { + Container::new() + .width(pct(100)) + .overflow(Overflow::Visible, Overflow::Scroll) + .push( + Container::new() + .display(Display::Flex) + .width(pct(100)) + .margin(Unit::Px(0.0), Unit::Auto, Unit::Px(0.0), Unit::Auto) + .flex_direction(FlexDirection::Column) + .flex_grow(1.0) + .push(hero_intro(navigate_fn)) + .push(hero_features()), + ) +} diff --git a/website/src/link.rs b/website/src/link.rs new file mode 100644 index 00000000..519d0250 --- /dev/null +++ b/website/src/link.rs @@ -0,0 +1,18 @@ +use std::rc::Rc; + +use craft_retained::elements::{Container, Element}; +use craft_retained::events::ui_events::pointer::PointerButton; + +#[allow(non_snake_case)] +pub fn Link(on_click: F) -> Container +where + F: Fn() + 'static, +{ + let on_click = Rc::new(on_click); + + Container::new().on_pointer_button_up(Rc::new(move |_event, pointer_button_event| { + if pointer_button_event.button == Some(PointerButton::Primary) { + on_click(); + } + })) +} diff --git a/website/src/main.rs b/website/src/main.rs new file mode 100644 index 00000000..2bb7851c --- /dev/null +++ b/website/src/main.rs @@ -0,0 +1,89 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use craft_retained::{CraftOptions, craft_main}; + +use crate::router::Router; + +mod docs; +mod examples; +mod index; +mod link; +mod navbar; +mod router; +mod theme; +mod web_link; + +pub(crate) struct WebsiteGlobalState { + /// The current route that we are viewing. + route: String, +} + +impl WebsiteGlobalState { + pub(crate) fn get_route(&self) -> String { + #[cfg(target_arch = "wasm32")] + let path: String; + #[cfg(target_arch = "wasm32")] + { + let window = web_sys::window().expect("No window available."); + path = window + .location() + .pathname() + .map(|s| { + let trimmed_path = s.trim_end_matches('/'); + if trimmed_path.is_empty() { + "/".to_string() + } else { + trimmed_path.to_string() + } + }) + .unwrap_or("/".to_string()); + } + #[cfg(not(target_arch = "wasm32"))] + let path = self.route.clone(); + path + } + + pub(crate) fn set_route(&mut self, route: &str) { + self.route = route.to_string(); + + #[cfg(target_arch = "wasm32")] + { + let window = web_sys::window().unwrap(); + let history = window.history().unwrap(); + + history + .push_state_with_url(&web_sys::wasm_bindgen::JsValue::NULL, "", Some(route)) + .unwrap(); + } + } + + pub fn load_route(&mut self) { + #[cfg(not(target_arch = "wasm32"))] + { + // NOTE: In Git Bash, use `cargo run -- //examples`. + let route = std::env::args().nth(1).unwrap_or_else(|| "/".to_string()); + self.set_route(route.as_str()); + } + #[cfg(target_arch = "wasm32")] + self.set_route(&self.get_route()); + } +} + +impl Default for WebsiteGlobalState { + fn default() -> Self { + WebsiteGlobalState { + route: "/".to_string(), + } + } +} + +fn main() { + util::setup_logging(); + + let global_state = Rc::new(RefCell::new(WebsiteGlobalState::default())); + global_state.borrow_mut().load_route(); + let page_wrapper = Router::new(global_state); + page_wrapper.borrow().navigate(); + craft_main(CraftOptions::default()); +} diff --git a/website/src/navbar.rs b/website/src/navbar.rs new file mode 100644 index 00000000..8512cdf4 --- /dev/null +++ b/website/src/navbar.rs @@ -0,0 +1,69 @@ +use crate::link::Link; +use crate::router::NavigateFn; +use crate::theme::{NAVBAR_BACKGROUND_COLOR, NAVBAR_TEXT_COLOR, wrapper}; +use craft_retained::elements::{Container, Element, Text}; +use craft_retained::style::{AlignItems, Display, FontWeight, JustifyContent, Unit}; +use craft_retained::{pct, px, rgb}; + +pub const NAVBAR_HEIGHT: f32 = 60.0; + +fn create_link(navigate_fn: NavigateFn, label: &str, route: &str) -> Container { + let route_owned = route.to_string(); + let nav = navigate_fn.clone(); + Link(move || { + nav(&route_owned); + }) + .push( + Text::new(label) + .id(format!("route_{route}").as_str()) + .margin(px(0), px(12), px(0), px(0)) + .font_size(16.0) + .selectable(false) + .color(NAVBAR_TEXT_COLOR), + ) + /*.hovered() + .color(NAVBAR_TEXT_HOVERED_COLOR) + .underline(1.0, Color::BLACK, None) + .margin(px(0), "12px", px(0), px(0)) + .font_size(16.5) + .disable_selection() + .normal()*/ +} + +pub fn navbar(navigate_fn: NavigateFn) -> Container { + let border_color = rgb(240, 240, 240); + let container = Container::new() + .width(pct(100)) + .height(Unit::Px(NAVBAR_HEIGHT)) + .min_height(Unit::Px(NAVBAR_HEIGHT)) + .max_height(Unit::Px(NAVBAR_HEIGHT)) + .border_width(px(0), px(0), px(2), px(0)) + .border_color(border_color, border_color, border_color, border_color) + .background_color(NAVBAR_BACKGROUND_COLOR); + + let wrapper = wrapper() + .display(Display::Flex) + .justify_content(Some(JustifyContent::SpaceBetween)) + .align_items(Some(AlignItems::Center)) + // Left + .push( + Container::new() + .display(Display::Flex) + .justify_content(Some(JustifyContent::Center)) + .align_items(Some(AlignItems::Center)) + .push( + create_link(navigate_fn.clone(), "Craft", "/") + .font_size(32.0) + .font_weight(FontWeight::BOLD) + .margin(px(0), px(24), px(0), px(0)), /*.hovered() + .font_size(32.0) + .font_weight(Weight::BOLD) + .margin(px(0), "24px", px(0), px(0)),*/ + ) + .push(create_link(navigate_fn.clone(), "Home", "/").margin(px(0), px(12), px(0), px(0))) + .push(create_link(navigate_fn.clone(), "Docs", "/docs").margin(px(0), px(12), px(0), px(0))) + .push(create_link(navigate_fn.clone(), "Examples", "/examples").margin(px(0), px(12), px(0), px(0))), + ); + + container.push(wrapper) +} diff --git a/website/src/router.rs b/website/src/router.rs new file mode 100644 index 00000000..9f0c85c2 --- /dev/null +++ b/website/src/router.rs @@ -0,0 +1,84 @@ +use craft_retained::elements::{Container, Element, Window}; +use craft_retained::pct; +use craft_retained::style::{Display, FlexDirection}; +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +use crate::WebsiteGlobalState; +use crate::docs::docs; +use crate::examples::examples; +use crate::index::index_page; +use crate::navbar::navbar; +use crate::theme::BODY_BACKGROUND_COLOR; + +#[derive(Clone)] +pub struct Router { + pub root: Window, + global_state: Rc>, + index: Container, + docs: Container, + examples: Container, +} + +pub type NavigateFn = Rc; + +impl Router { + pub fn new(global_state: Rc>) -> Rc> { + let state = global_state.clone(); + Rc::new_cyclic(|me: &Weak>| { + let me = me.clone(); + + let navigate_logic: NavigateFn = Rc::new(move |route| { + state.borrow_mut().set_route(route); + if let Some(router) = me.upgrade() { + router.borrow().navigate(); + } + }); + + let window = Window::new("Craft Gui") + .display(Display::Flex) + .flex_direction(FlexDirection::Column) + .width(pct(100)) + .height(pct(100)) + .push(navbar(navigate_logic.clone())) + .background_color(BODY_BACKGROUND_COLOR); + + RefCell::new(Self { + root: window.clone(), + index: index_page(navigate_logic.clone()), + docs: docs(navigate_logic.clone()), + examples: examples(global_state.clone(), navigate_logic.clone()), + global_state: global_state.clone(), + }) + }) + } + + fn set_content(&self, container: Container) { + if let Some(current_content) = self.root.get_children().get(1) { + self.root + .remove_child(current_content.clone()) + .expect("Failed to remove child"); + } + self.root.clone().push(container); + } + + pub fn navigate(&self) { + let global_state = self.global_state.borrow(); + let full_route = global_state.route.as_str(); + + let base_route = full_route.split('/').find(|s| !s.is_empty()).unwrap_or(""); + + let page = match base_route { + "" => self.index.clone(), + "docs" => self.docs.clone(), + "examples" => self.examples.clone(), + _ => self.index.clone(), + }; + + self.set_content(page); + } + + /*pub fn window(&self) -> Arc { + self.root.inner.borrow().winit_window().expect("No widow") + }*/ +} diff --git a/website/src/theme.rs b/website/src/theme.rs new file mode 100644 index 00000000..3a95bfd9 --- /dev/null +++ b/website/src/theme.rs @@ -0,0 +1,33 @@ +use craft_retained::elements::{Container, Element}; +use craft_retained::style::Unit; +use craft_retained::{Color, pct}; + +pub(crate) const BODY_BACKGROUND_COLOR: Color = Color::from_rgb8(255, 255, 255); + +pub(crate) const NAVBAR_BACKGROUND_COLOR: Color = Color::from_rgb8(255, 255, 255); +pub(crate) const NAVBAR_TEXT_COLOR: Color = Color::from_rgb8(50, 50, 50); +//pub(crate) const NAVBAR_TEXT_HOVERED_COLOR: Color = Color::from_rgb8(0, 0, 0); + +pub(crate) const ACTIVE_LINK_COLOR: Color = Color::from_rgb8(42, 108, 200); +pub(crate) const DEFAULT_LINK_COLOR: Color = Color::from_rgb8(102, 102, 102); + +pub(crate) const WRAPPER_MAX_WIDTH: Unit = Unit::Px(1300.0); +pub(crate) const WRAPPER_MARGIN_LEFT: Unit = Unit::Auto; +pub(crate) const WRAPPER_MARGIN_RIGHT: Unit = Unit::Auto; +pub(crate) const WRAPPER_PADDING_LEFT: Unit = Unit::Px(20.0); +pub(crate) const WRAPPER_PADDING_RIGHT: Unit = Unit::Px(20.0); + +//pub(crate) const MOBILE_MEDIA_QUERY_WIDTH: u32 = 850; + +pub(crate) fn wrapper() -> Container { + Container::new() + .margin(Unit::Px(0.0), WRAPPER_MARGIN_RIGHT, Unit::Px(0.0), WRAPPER_MARGIN_LEFT) + .padding( + Unit::Px(0.0), + WRAPPER_PADDING_RIGHT, + Unit::Px(0.0), + WRAPPER_PADDING_LEFT, + ) + .width(pct(100)) + .max_width(WRAPPER_MAX_WIDTH) +} diff --git a/website/src/web_link.rs b/website/src/web_link.rs new file mode 100644 index 00000000..564fbdc6 --- /dev/null +++ b/website/src/web_link.rs @@ -0,0 +1,26 @@ +use std::rc::Rc; + +use craft_retained::elements::{Container, Element}; +use craft_retained::events::ui_events::pointer::PointerButton; + +#[allow(non_snake_case)] +pub fn WebLink(href: &str) -> Container { + let href = href.to_string(); + + Container::new().on_pointer_button_up(Rc::new(move |_event, pointer_button_event| { + if pointer_button_event.button == Some(PointerButton::Primary) { + #[cfg(target_arch = "wasm32")] + { + if let Some(win) = web_sys::window() { + // Use the captured owned string + let _ = win.open_with_url(&href); + } + } + + #[cfg(not(target_arch = "wasm32"))] + { + open::that(&href).unwrap(); + } + } + })) +} diff --git a/website/wasm-build.sh b/website/wasm-build.sh new file mode 100644 index 00000000..901b25f1 --- /dev/null +++ b/website/wasm-build.sh @@ -0,0 +1,12 @@ +set -e + + +#rustup target add wasm32-unknown-unknown +#cargo install -f wasm-bindgen-cli +#cargo install simple-http-server + +cargo build --target wasm32-unknown-unknown --release + +wasm-bindgen ../target/wasm32-unknown-unknown/release/website.wasm --target web --no-typescript --out-dir dist --out-name website --debug --keep-debug +cp index.html dist/index.html +simple-http-server dist -c wasm,html,js --try-file dist/index.html -i --coep --coop --ip 0.0.0.0 \ No newline at end of file diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000..29c4e318 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "xtask" +publish = false +version = "0.1.0" +edition = "2024" + +[dependencies] +clap = { version = "4.5", features = ["derive"] } +kompari = { git = "https://github.com/linebender/kompari.git", rev = "63476ab8a6413cd5add210b76c1d2d671dd67212" } +kompari-tasks = { git = "https://github.com/linebender/kompari.git", rev = "63476ab8a6413cd5add210b76c1d2d671dd67212" } \ No newline at end of file diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000..919460a9 --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,43 @@ +// Copyright 2024 the Kompari Authors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::path::Path; +use std::process::Command; + +use clap::Parser; +use kompari::DirDiffConfig; +use kompari_tasks::{Actions, Args, Task}; + +struct ActionsImpl(); + +impl Actions for ActionsImpl { + fn generate_all_tests(&self) -> kompari::Result<()> { + let cargo = std::env::var("CARGO").unwrap(); + Command::new(&cargo) + .arg("test") + .arg("--test") + .arg("counter") + .env("CRAFT_RETAINED_TEST", "generate-all") + .status()?; + Ok(()) + } +} + +fn main() -> kompari::Result<()> { + let tests_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("crates") + .join("craft_retained") + .join("tests"); + + let snapshots_path = tests_path.join("snapshots"); + let current_path = tests_path.join("current"); + + let args = Args::parse(); + let diff_config = DirDiffConfig::new(snapshots_path, current_path); + let actions = ActionsImpl(); + let mut task = Task::new(diff_config, Box::new(actions)); + task.run(&args)?; + Ok(()) +}