From 34333eec3b3ad95b7bf7a7abd472915624686470 Mon Sep 17 00:00:00 2001 From: Shark Date: Thu, 2 May 2024 11:27:22 +0200 Subject: [PATCH 1/2] image rendering Signed-off-by: Shark --- Cargo.lock | 543 ++++++++++++++++++++++- crates/gosub_net/src/http.rs | 2 + crates/gosub_renderer/Cargo.toml | 3 + crates/gosub_renderer/src/draw.rs | 165 ++++++- crates/gosub_renderer/src/render_tree.rs | 5 +- src/bin/renderer.rs | 5 +- src/bin/resources/gosub.html | 49 +- 7 files changed, 706 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff118026a..e28c8a876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,6 +96,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -130,7 +136,7 @@ dependencies = [ "encoding_rs", "flate2", "glyph-names", - "itertools", + "itertools 0.10.5", "lazy_static", "libc", "log", @@ -240,6 +246,23 @@ version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -290,6 +313,29 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -332,6 +378,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -353,6 +405,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "bitstream-io" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c9989a51171e2e81038ab168b6ae22886fe9ded214430dbb4f41c28cf176da" + [[package]] name = "block" version = "0.1.6" @@ -397,6 +455,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41bfbdb21256b87a8b5e80fab81a8eed158178e812fd7ba451907518b2742f16" + [[package]] name = "bumpalo" version = "3.15.3" @@ -435,6 +499,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.5.0" @@ -489,6 +559,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -594,6 +674,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.0" @@ -779,7 +865,7 @@ dependencies = [ "clap", "criterion-plot", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -800,7 +886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -989,6 +1075,31 @@ dependencies = [ "num-traits", ] +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + [[package]] name = "flate2" version = "1.0.28" @@ -999,6 +1110,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1200,6 +1320,16 @@ dependencies = [ "polyval", ] +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.28.1" @@ -1373,12 +1503,15 @@ dependencies = [ "anyhow", "futures", "gosub_html5", + "gosub_net", "gosub_rendering", "gosub_shared", "gosub_styling", + "image", "slotmap", "smallvec", "taffy", + "url", "vello", "wasm-bindgen-futures", "web-sys", @@ -1741,6 +1874,45 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "image" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +dependencies = [ + "byteorder-lite", + "thiserror", +] + +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "indexmap" version = "2.2.5" @@ -1760,6 +1932,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -1798,6 +1981,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1835,6 +2027,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.69" @@ -1877,12 +2075,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + [[package]] name = "libloading" version = "0.7.4" @@ -1942,6 +2157,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru-cache" version = "0.1.2" @@ -1966,6 +2190,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.1" @@ -2009,6 +2243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", + "simd-adler32", ] [[package]] @@ -2082,6 +2317,12 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nom" version = "7.1.3" @@ -2103,12 +2344,61 @@ dependencies = [ "nom", ] +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -2401,6 +2691,19 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "polling" version = "3.6.0" @@ -2453,7 +2756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -2494,6 +2797,28 @@ name = "profiling" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn 2.0.58", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] [[package]] name = "quick-error" @@ -2501,6 +2826,12 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.31.0" @@ -2586,6 +2917,56 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error 2.0.1", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "raw-window-handle" version = "0.6.0" @@ -2681,7 +3062,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ "hostname", - "quick-error", + "quick-error 1.2.3", +] + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", ] [[package]] @@ -2854,6 +3244,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2865,6 +3264,21 @@ dependencies = [ "digest", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simple_logger" version = "4.3.3" @@ -2965,6 +3379,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spirv" @@ -3055,6 +3472,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + [[package]] name = "taffy" version = "0.4.3" @@ -3068,6 +3498,12 @@ dependencies = [ "slotmap", ] +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + [[package]] name = "termcolor" version = "1.4.1" @@ -3139,6 +3575,17 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.34" @@ -3238,11 +3685,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.12", +] + [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -3252,7 +3714,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.7", ] [[package]] @@ -3435,6 +3910,17 @@ dependencies = [ "which", ] +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "vello" version = "0.1.0" @@ -3462,6 +3948,12 @@ dependencies = [ "skrifa", ] +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.4" @@ -3688,6 +4180,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "wgpu" version = "0.19.3" @@ -4125,6 +4623,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -4249,3 +4756,27 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] diff --git a/crates/gosub_net/src/http.rs b/crates/gosub_net/src/http.rs index 0ea737810..5d53d779a 100644 --- a/crates/gosub_net/src/http.rs +++ b/crates/gosub_net/src/http.rs @@ -1,3 +1,5 @@ +pub use ureq; + pub mod headers; pub mod request; pub mod response; diff --git a/crates/gosub_renderer/Cargo.toml b/crates/gosub_renderer/Cargo.toml index 915ef746c..9c010305b 100644 --- a/crates/gosub_renderer/Cargo.toml +++ b/crates/gosub_renderer/Cargo.toml @@ -12,6 +12,7 @@ gosub_rendering = { path = "../gosub_rendering" } gosub_html5 = { path = "../gosub_html5" } gosub_shared = { path = "../gosub_shared" } gosub_styling = { path = "../gosub_styling" } +gosub_net = { path = "../gosub_net" } taffy = "0.4.1" vello = "0.1.0" winit = "0.29.15" @@ -20,6 +21,8 @@ wgpu = "0.19.3" futures = "0.3.30" slotmap = "1.0.7" smallvec = "1.13.2" +image = "0.25.1" +url = "2.5.0" diff --git a/crates/gosub_renderer/src/draw.rs b/crates/gosub_renderer/src/draw.rs index f02e91f3b..4be9e1c1e 100644 --- a/crates/gosub_renderer/src/draw.rs +++ b/crates/gosub_renderer/src/draw.rs @@ -1,9 +1,12 @@ +use std::io::Read; +use std::ops::Div; + use anyhow::anyhow; use smallvec::SmallVec; -use std::ops::Div; use taffy::{AvailableSpace, Layout, NodeId, PrintTree, Size, TaffyTree, TraversePartialTree}; +use url::Url; use vello::kurbo::{Affine, Arc, BezPath, Cap, Join, Rect, RoundedRect, Stroke}; -use vello::peniko::{Color, Fill}; +use vello::peniko::{Color, Fill, Format, Image}; use vello::Scene; use winit::dpi::PhysicalSize; @@ -93,10 +96,52 @@ impl TreeDrawer { pos.0 += layout.location.x as f64; pos.1 += layout.location.y as f64; - render_text(node, scene, pos, layout); - let border_radius = render_bg(node, scene, layout, pos); + if let RenderNodeData::Element(element) = &node.data { + if element.name() == "img" { + let src = element + .attributes + .get("src") + .ok_or(anyhow!("Image element has no src attribute"))?; + + let url = Url::parse(src.as_str()).or_else(|_| self.url.join(src.as_str()))?; + + let res = gosub_net::http::ureq::get(url.as_str()).call()?; + + let mut img = Vec::with_capacity( + res.header("Content-Length") + .unwrap_or("1024") + .parse::()?, + ); + + res.into_reader().read_to_end(&mut img)?; + + let img = image::load_from_memory(&img)?; + img.save("test.png")?; + + let width = img.width(); + let height = img.height(); + + let img = Image::new( + img.into_rgba8().into_raw().into(), + Format::Rgba8, + width, + height, + ); + + let fit = element + .attributes + .get("object-fit") + .map(|prop| prop.as_str()) + .unwrap_or("contain"); + + render_image(&img, scene, *pos, layout.size, border_radius, fit)?; + } + } + + render_text(node, scene, pos, layout); + render_border(node, scene, layout, pos, border_radius); Ok(()) @@ -131,7 +176,7 @@ fn render_bg( scene: &mut Scene, layout: &Layout, pos: &(f64, f64), -) -> f64 { +) -> (f64, f64, f64, f64) { let bg_color = node .properties .get("background-color") @@ -146,15 +191,49 @@ fn render_bg( }) .map(|color| Color::rgba8(color.r as u8, color.g as u8, color.b as u8, color.a as u8)); - let border_radius = node + let border_radius_left = node + .properties + .get("border-radius-left") + .map(|prop| { + prop.compute_value(); + prop.actual.unit_to_px() as f64 + }) + .unwrap_or(0.0); + + let border_radius_right = node + .properties + .get("border-radius-right") + .map(|prop| { + prop.compute_value(); + prop.actual.unit_to_px() as f64 + }) + .unwrap_or(0.0); + + let border_radius_top = node + .properties + .get("border-radius-top") + .map(|prop| { + prop.compute_value(); + prop.actual.unit_to_px() as f64 + }) + .unwrap_or(0.0); + + let border_radius_bottom = node .properties - .get("border-radius") + .get("border-radius-bottom") .map(|prop| { prop.compute_value(); prop.actual.unit_to_px() as f64 }) .unwrap_or(0.0); + let border_radius = ( + border_radius_top, + border_radius_right, + border_radius_bottom, + border_radius_left, + ); + if let Some(bg_color) = bg_color { let rect = RoundedRect::new( pos.0, @@ -196,10 +275,16 @@ fn render_border( scene: &mut Scene, layout: &Layout, pos: &(f64, f64), - border_radius: f64, + border_radius: (f64, f64, f64, f64), ) { for side in Side::all() { - render_border_side(node, scene, layout, pos, border_radius, side); + let radi = match side { + Side::Top => border_radius.0, + Side::Right => border_radius.1, + Side::Bottom => border_radius.2, + Side::Left => border_radius.3, + }; + render_border_side(node, scene, layout, pos, radi, side); } } @@ -425,6 +510,68 @@ fn render_border_side( } } +fn render_image( + img: &Image, + scene: &mut Scene, + pos: (f64, f64), + size: Size, + radii: (f64, f64, f64, f64), + fit: &str, +) -> anyhow::Result<()> { + let width = size.width as f64; + let height = size.height as f64; + + let rect = RoundedRect::new(pos.0, pos.1, pos.0 + width, pos.1 + height, radii); + + let affine = match fit { + "fill" => { + let scale_x = width / img.width as f64; + let scale_y = height / img.height as f64; + + Affine::scale_non_uniform(scale_x, scale_y) + } + "contain" => { + let scale_x = width / img.width as f64; + let scale_y = height / img.height as f64; + + let scale = scale_x.min(scale_y); + + Affine::scale_non_uniform(scale, scale) + } + "cover" => { + let scale_x = width / img.width as f64; + let scale_y = height / img.height as f64; + + let scale = scale_x.max(scale_y); + + Affine::scale_non_uniform(scale, scale) + } + "scale-down" => { + let scale_x = width / img.width as f64; + let scale_y = height / img.height as f64; + + let scale = scale_x.min(scale_y); + let scale = scale.min(1.0); + + Affine::scale_non_uniform(scale, scale) + } + _ => Affine::IDENTITY, + }; + + let affine = affine.with_translation(pos.into()); + + println!("affine: {:?}", affine); + println!("fit: {:?}", fit); + println!("width: {:?}", width); + println!("height: {:?}", height); + println!("img size: {}x{}", img.width, img.height); + println!("rect: {:?}", rect); + + scene.fill(Fill::NonZero, Affine::IDENTITY, img, Some(affine), &rect); + + Ok(()) +} + #[derive(Debug)] enum BorderStyle { None, diff --git a/crates/gosub_renderer/src/render_tree.rs b/crates/gosub_renderer/src/render_tree.rs index b4f682897..3c5b80d1c 100644 --- a/crates/gosub_renderer/src/render_tree.rs +++ b/crates/gosub_renderer/src/render_tree.rs @@ -1,5 +1,6 @@ use taffy::NodeId as TaffyID; use taffy::{Layout, TaffyTree}; +use url::Url; use winit::dpi::PhysicalSize; use gosub_html5::node::NodeId as GosubID; @@ -13,15 +14,17 @@ pub struct TreeDrawer { pub(crate) root: NodeID, pub(crate) taffy: TaffyTree, pub(crate) size: Option>, + pub(crate) url: Url, } impl TreeDrawer { - pub fn new(style: StyleTree, taffy: TaffyTree, root: TaffyID) -> Self { + pub fn new(style: StyleTree, taffy: TaffyTree, root: TaffyID, url: Url) -> Self { Self { style, root, taffy, size: None, + url, } } } diff --git a/src/bin/renderer.rs b/src/bin/renderer.rs index 1ad03709e..c881a0e16 100644 --- a/src/bin/renderer.rs +++ b/src/bin/renderer.rs @@ -1,6 +1,8 @@ use std::fs; use anyhow::bail; +use url::Url; + use gosub_html5::parser::document::{Document, DocumentBuilder}; use gosub_html5::parser::Html5Parser; use gosub_renderer::render_tree::TreeDrawer; @@ -10,7 +12,6 @@ use gosub_shared::bytes::CharIterator; use gosub_shared::bytes::{Confidence, Encoding}; use gosub_shared::types::Result; use gosub_styling::render_tree::{generate_render_tree, RenderTree as StyleTree}; -use url::Url; fn main() -> Result<()> { let matches = clap::Command::new("Gosub Renderer") @@ -28,7 +29,7 @@ fn main() -> Result<()> { let (taffy_tree, root) = generate_taffy_tree(&mut rt)?; - let render_tree = TreeDrawer::new(rt, taffy_tree, root); + let render_tree = TreeDrawer::new(rt, taffy_tree, root, Url::parse("https://gosub.io/")?); let render_tree = render_tree; diff --git a/src/bin/resources/gosub.html b/src/bin/resources/gosub.html index 368b732b2..e3df2af27 100644 --- a/src/bin/resources/gosub.html +++ b/src/bin/resources/gosub.html @@ -30,7 +30,6 @@ } h1 { - color: darkcyan; font-size: 96px; padding-bottom: 0; padding-left: 0; @@ -39,11 +38,6 @@ margin-bottom: 0; margin-left: 0; margin-right: 0; - border-width: 8px; - border-top-width: 8px; - border-color: green; - border-style: solid; - background-color: #0c3ebb44; } blockquote { @@ -76,15 +70,8 @@ color: cyan; text-decoration: none; + border-bottom-color: #6e40c9; border-bottom-width: 2px; - border-top-width: 2px; - border-left-width: 2px; - border-right-width: 2px; - - - border-top-style: dashed; - border-right-style: solid; - border-left-style: solid; border-bottom-style: solid; font-family: "Verdana", sans-serif; @@ -94,24 +81,6 @@ /*width: min-content;*/ } - #link1 { - /*border-top-color: red;*/ - /*border-left-color: green;*/ - /*border-right-color: orange;*/ - border-bottom-color: yellow; - width: 100px; - border-radius: 8px; - background-color: #ff8000aa; - } - - #link2 { - border-color: #7289da; - } - - #link3 { - border-color: #401e98; - } - a:link { text-decoration: none; } @@ -131,21 +100,6 @@ .logo { width: 400px; height: 500px; - /*aspect-ratio: 1/2;*/ - background-color: #ff8000; - border-radius: 64px; - border-top-color: #ffff00; - border-top-width: 2px; - border-top-style: dashed; - border-right-color: #22FF00; - border-right-width: 2px; - border-right-style: solid; - border-left-color: #00FFFF; - border-left-width: 16px; - border-left-style: solid; - border-bottom-color: #FF00FF; - border-bottom-width: 2px; - border-bottom-style: double; } textarea { @@ -193,7 +147,6 @@

Gosub

  • Developer chat - Zulip
  • - \ No newline at end of file From f6d2426458aa52264bfcc1d8287d111d713c054d Mon Sep 17 00:00:00 2001 From: Shark Date: Thu, 2 May 2024 12:08:12 +0200 Subject: [PATCH 2/2] support background-image: url() Signed-off-by: Shark --- crates/gosub_renderer/src/draw.rs | 62 ++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/crates/gosub_renderer/src/draw.rs b/crates/gosub_renderer/src/draw.rs index 4be9e1c1e..85bb7f32e 100644 --- a/crates/gosub_renderer/src/draw.rs +++ b/crates/gosub_renderer/src/draw.rs @@ -96,7 +96,7 @@ impl TreeDrawer { pos.0 += layout.location.x as f64; pos.1 += layout.location.y as f64; - let border_radius = render_bg(node, scene, layout, pos); + let border_radius = render_bg(node, scene, layout, pos, &self.url); if let RenderNodeData::Element(element) = &node.data { if element.name() == "img" { @@ -118,7 +118,6 @@ impl TreeDrawer { res.into_reader().read_to_end(&mut img)?; let img = image::load_from_memory(&img)?; - img.save("test.png")?; let width = img.width(); let height = img.height(); @@ -176,6 +175,7 @@ fn render_bg( scene: &mut Scene, layout: &Layout, pos: &(f64, f64), + root_url: &Url, ) -> (f64, f64, f64, f64) { let bg_color = node .properties @@ -234,17 +234,61 @@ fn render_bg( border_radius_left, ); + let rect = RoundedRect::new( + pos.0, + pos.1, + pos.0 + layout.size.width as f64, + pos.1 + layout.size.height as f64, + border_radius, + ); + if let Some(bg_color) = bg_color { - let rect = RoundedRect::new( - pos.0, - pos.1, - pos.0 + layout.size.width as f64, - pos.1 + layout.size.height as f64, - border_radius, - ); scene.fill(Fill::NonZero, Affine::IDENTITY, bg_color, None, &rect); } + let background_image = node.properties.get("background-image").and_then(|prop| { + prop.compute_value(); + + match &prop.actual { + CssValue::String(url) => Some(url.as_str()), + _ => None, + } + }); + + if let Some(url) = background_image { + let Ok(url) = Url::parse(url).or_else(|_| root_url.join(url)) else { + eprintln!("TODO: Add Image not found Image"); + return border_radius; + }; + + let res = gosub_net::http::ureq::get(url.as_str()).call().unwrap(); + + let mut img = Vec::with_capacity( + res.header("Content-Length") + .unwrap_or("1024") + .parse::() + .unwrap(), + ); + + res.into_reader().read_to_end(&mut img).unwrap(); + + let img = image::load_from_memory(&img).unwrap(); + + let height = img.height(); + let width = img.width(); + + let img = Image::new( + img.into_rgba8().into_raw().into(), + Format::Rgba8, + width, + height, + ); + + let _ = render_image(&img, scene, *pos, layout.size, border_radius, "fill").map_err(|e| { + eprintln!("Error rendering image: {:?}", e); + }); + } + border_radius }