Merge remote-tracking branch 'hardiesoft/swf_renderer'

This commit is contained in:
Patrick Walton 2019-06-21 09:25:00 -07:00
commit 82b0826407
10 changed files with 1178 additions and 21 deletions

160
Cargo.lock generated
View File

@ -44,7 +44,7 @@ name = "approx"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -90,7 +90,7 @@ dependencies = [
[[package]]
name = "autocfg"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -98,7 +98,7 @@ name = "backtrace"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
@ -142,6 +142,11 @@ name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "build_const"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.1"
@ -251,7 +256,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -366,6 +371,14 @@ dependencies = [
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crc"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crc32fast"
version = "1.2.0"
@ -545,7 +558,7 @@ version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -815,6 +828,11 @@ dependencies = [
"gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "half"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "harfbuzz"
version = "0.3.1"
@ -855,6 +873,11 @@ dependencies = [
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "humantime"
version = "1.2.0"
@ -875,7 +898,7 @@ dependencies = [
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -889,7 +912,7 @@ dependencies = [
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1017,7 +1040,7 @@ name = "line_drawing"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1059,7 +1082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1070,6 +1093,16 @@ dependencies = [
"lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzma-rs"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzw"
version = "0.10.0"
@ -1158,6 +1191,15 @@ name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.42"
@ -1165,7 +1207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1183,7 +1225,7 @@ name = "num-integer"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1192,7 +1234,7 @@ version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1201,7 +1243,7 @@ version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1210,13 +1252,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.6"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
@ -1271,7 +1316,7 @@ name = "ordered-float"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1371,6 +1416,18 @@ dependencies = [
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pathfinder_flash"
version = "0.1.0"
dependencies = [
"pathfinder_geometry 0.3.0",
"pathfinder_gl 0.1.0",
"pathfinder_gpu 0.1.0",
"pathfinder_renderer 0.1.0",
"swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pathfinder_geometry"
version = "0.3.0"
@ -1610,7 +1667,7 @@ name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1628,7 +1685,7 @@ name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1689,7 +1746,7 @@ name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2029,6 +2086,58 @@ dependencies = [
"phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "swf-fixed"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "swf-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "swf-tree"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "swf_basic"
version = "0.1.0"
dependencies = [
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_flash 0.1.0",
"pathfinder_geometry 0.3.0",
"pathfinder_gl 0.1.0",
"pathfinder_gpu 0.1.0",
"pathfinder_renderer 0.1.0",
"sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.34"
@ -2388,13 +2497,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
"checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
@ -2413,6 +2523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
"checksum core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d95a72b5e50e549969dd88eff3047495fe5b8c6f028635442c2b708be707e669"
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
@ -2458,10 +2569,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89996c30857ae1b4de4b5189abf1ea822a20a9fe9e1c93e5e7b862ff0bdd5cdf"
"checksum glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1290a5ca5e46fcfa7f66f949cc9d9194b2cb6f2ed61892c8c2b82343631dba57"
"checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021"
"checksum half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9353c2a89d550b58fa0061d8ed8d002a7d8cdf2494eb0e432859bd3a9e543836"
"checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da"
"checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961"
"checksum harfbuzz_rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "534c8e9b15d8db6e69654b07dad955f4132757194e7d2bba620d38cf08996088"
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a"
"checksum image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116"
@ -2487,6 +2600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ea0ba5f8d2d91d6d895aca54d1ec0d84ddfa4826f33fbfe8abb39f08f9e4153"
"checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843"
"checksum lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9550ba35a4d6bb6be7f273bce93af3a3141c517bf7d7298763a7149e1bdb9af5"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
@ -2498,13 +2612,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98"
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
@ -2576,6 +2691,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum svgdom 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ddce601e49ed213b0126ff4172cd9f5f8dba5f1df2277ecbe0e298f9865baba"
"checksum svgtypes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "444c882c28925ae0585df228a90f9951569588646ceca4753560de93cdd02258"
"checksum swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3c575807f18641c5e079568b53630a46baf441da57caccd9ced9a9ee70f941"
"checksum swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6349830c1ed5d26b97d801e3fb8664556e12a01560e3479e3961e8f5675a05"
"checksum swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c075cea0328cc5f6ee694bcd1c43534d1186a730d79258b10735f8f08e2f1baa"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"

View File

@ -12,9 +12,11 @@ members = [
"examples/canvas_moire",
"examples/canvas_text",
"examples/lottie_basic",
"examples/swf_basic",
"geometry",
"gl",
"gpu",
"flash",
"lottie",
"metal",
"renderer",

View File

@ -0,0 +1,28 @@
[package]
name = "swf_basic"
version = "0.1.0"
authors = ["Jon Hardie <jon@hardiesoft.com>"]
edition = "2018"
[dependencies]
gl = "0.6"
sdl2 = "0.32"
sdl2-sys = "0.32"
swf-parser = "0.7.0"
swf-tree = "0.7.0"
[dependencies.pathfinder_flash]
path = "../../flash"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_renderer]
path = "../../renderer"

View File

@ -0,0 +1,135 @@
// pathfinder/examples/swf_basic/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::options::{RenderTransform, BuildOptions};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
use pathfinder_renderer::scene::Scene;
use pathfinder_flash::{draw_paths_into_scene, process_swf_tags};
use std::env;
use std::fs::read;
use pathfinder_geometry::basic::transform2d::Transform2DF;
fn main() {
let swf_bytes;
if let Some(path) = env::args().skip(1).next() {
match read(path) {
Ok(bytes) => {
swf_bytes = bytes;
},
Err(e) => panic!(e)
}
} else {
// NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single
// layer with no overlapping shapes. This is how artwork is 'natively' created in the Flash
// authoring tool when an artist just draws directly onto the canvas (without 'object' mode
// turned on, which is the default).
// Subsequent shapes with different fills will knock out existing fills where they overlap.
// A downside of this in current pathfinder is that cracks are visible between shape fills -
// especially obvious if you set the context clear color to #ff00ff or similar.
// Common speculation as to why the swf format stores vector graphics in this way says that
// it is to save on file-size bytes, however in the case of our tiger, it results in a
// larger file than the layered version, since the overlapping shapes and strokes create
// a lot more geometry. I think a more likely explanation for the choice is that it was
// done to reduce overdraw in the software rasterizer running on late 90's era hardware?
// Indeed, this mode gives pathfinders' occlusion culling pass nothing to do!
//let default_tiger = include_bytes!("../swf/tiger-flat.swf");
// NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring
// tool from the SVG version loaded in Illustrator. When layered graphics are pasted
// into Flash, by default they retain their layering, expressed as groups.
// They are still presented as being on a single timeline layer.
// They will be drawn back to front in much the same way as the SVG version.
let default_tiger = include_bytes!("../swf/tiger.swf");
swf_bytes = Vec::from(&default_tiger[..]);
}
let (_, movie): (_, swf_tree::Movie) = swf_parser::parsers::movie::parse_movie(&swf_bytes[..]).unwrap();
// Set up SDL2.
let sdl_context = sdl2::init().unwrap();
let video = sdl_context.video().unwrap();
// Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core);
gl_attributes.set_context_version(3, 3);
// process swf scene
// TODO(jon): Since swf is a streaming format, this really wants to be a lazy iterator over
// swf frames eventually.
let (library, stage) = process_swf_tags(&movie);
// Open a window.
let window_size = Vector2I::new(stage.width(), stage.height());
let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32)
.opengl()
.allow_highdpi()
.build()
.unwrap();
let pixel_size = Vector2I::new(
window.drawable_size().0 as i32,
window.drawable_size().1 as i32
);
let device_pixel_ratio = pixel_size.x() as f32 / window_size.x() as f32;
// Create the GL context, and make it current.
let gl_context = window.gl_create_context().unwrap();
gl::load_with(|name| video.gl_get_proc_address(name) as *const _);
window.gl_make_current(&gl_context).unwrap();
// Create a Pathfinder renderer.
let mut renderer = Renderer::new(
GLDevice::new(GLVersion::GL3, 0),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(pixel_size),
RendererOptions { background_color: Some(stage.background_color()) }
);
// Clear to swf stage background color.
let mut scene = Scene::new();
scene.set_view_box(RectF::new(
Vector2F::default(),
Vector2F::new(
stage.width() as f32 * device_pixel_ratio,
stage.height() as f32 * device_pixel_ratio)
));
draw_paths_into_scene(&library, &mut scene);
// Render the canvas to screen.
let scene = SceneProxy::from_scene(scene, RayonExecutor);
let mut build_options = BuildOptions::default();
let scale_transform = Transform2DF::from_scale(
Vector2F::new(device_pixel_ratio, device_pixel_ratio)
);
build_options.transform = RenderTransform::Transform2D(scale_transform);
scene.build_and_render(&mut renderer, build_options);
window.gl_swap_window();
// Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap();
loop {
match event_pump.wait_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
_ => {}
}
}
}

Binary file not shown.

Binary file not shown.

21
flash/Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "pathfinder_flash"
version = "0.1.0"
authors = ["Jon Hardie <jon@hardiesoft.com>"]
edition = "2018"
[dependencies]
swf-parser = "0.7.0"
swf-tree = "0.7.0"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_renderer]
path = "../renderer"
[dependencies.pathfinder_gl]
path = "../gl"
[dependencies.pathfinder_gpu]
path = "../gpu"

206
flash/src/lib.rs Normal file
View File

@ -0,0 +1,206 @@
// pathfinder/flash/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::Add;
use pathfinder_geometry::color::{ColorU, ColorF};
use pathfinder_geometry::outline::{Outline, Contour};
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_renderer::scene::{PathObject, Scene};
use swf_tree;
use swf_tree::tags::SetBackgroundColor;
use swf_tree::{Tag, SRgb8, Movie};
use crate::shapes::{GraphicLayers, PaintOrLine};
mod shapes;
type SymbolId = u16;
// In swf, most values are specified in a fixed point format known as "twips" or twentieths of
// a pixel. We store twips in their integer form, as if we were to convert them to floating point
// at the beginning of the pipeline it's easy to start running into precision errors when we add
// coordinate deltas and then try and compare coords for equality.
#[derive(Copy, Clone, Debug, PartialEq)]
struct Twips(i32);
impl Twips {
// Divide twips by 20 to get the f32 value, just to be used once all processing
// of the swf coords is completed and we want to output.
fn as_f32(&self) -> f32 {
self.0 as f32 / 20.0
}
}
impl Add for Twips {
type Output = Twips;
fn add(self, rhs: Twips) -> Self {
Twips(self.0 + rhs.0)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
struct Point2<T> {
x: T,
y: T
}
impl Point2<Twips> {
fn as_f32(self: Point2<Twips>) -> Point2<f32> {
Point2 {
x: self.x.as_f32(),
y: self.y.as_f32(),
}
}
}
impl Add for Point2<Twips> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Point2 { x: self.x + rhs.x, y: self.y + rhs.y }
}
}
enum Symbol {
Graphic(GraphicLayers),
// Timeline, // TODO(jon)
}
pub struct Stage {
// TODO(jon): Support some kind of lazy frames iterator.
// frames: Timeline,
background_color: SRgb8,
width: i32,
height: i32,
}
impl Stage {
pub fn width(&self) -> i32 {
self.width
}
pub fn height(&self) -> i32 {
self.height
}
pub fn background_color(&self) -> ColorF {
ColorU {
r: self.background_color.r,
g: self.background_color.g,
b: self.background_color.b,
a: 255,
}.to_f32()
}
}
pub struct SymbolLibrary(Vec<Symbol>);
impl SymbolLibrary {
fn add_symbol(&mut self, symbol: Symbol) {
self.0.push(symbol);
}
fn symbols(&self) -> &Vec<Symbol> {
&self.0
}
}
pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) {
let mut symbol_library = SymbolLibrary(Vec::new());
let stage_width = Twips(movie.header.frame_size.x_max);
let stage_height = Twips(movie.header.frame_size.y_max);
// let num_frames = movie.header.frame_count;
let mut stage = Stage {
// frames: Timeline(Vec::new()), // TODO(jon)
background_color: SRgb8 {
r: 255,
g: 255,
b: 255
},
width: stage_width.as_f32() as i32,
height: stage_height.as_f32() as i32,
};
for tag in &movie.tags {
match tag {
Tag::SetBackgroundColor(SetBackgroundColor { color }) => {
stage.background_color = *color;
},
Tag::DefineShape(shape) => {
symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(&shape)));
// We will assume that symbol ids just go up, and are 1 based.
let symbol_id: SymbolId = shape.id;
debug_assert!(symbol_id as usize == symbol_library.0.len());
}
_ => ()
}
}
(symbol_library, stage)
}
#[allow(irrefutable_let_patterns)]
pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
for symbol in library.symbols() {
// NOTE: Right now symbols only contain graphics.
if let Symbol::Graphic(graphic) = symbol {
for style_layer in graphic.layers() {
let mut path = Outline::new();
let paint_id = scene.push_paint(&style_layer.fill());
for shape in style_layer.shapes() {
let mut contour = Contour::new();
let Point2 { x, y } = shape.outline.first().unwrap().from.as_f32();
contour.push_endpoint(Vector2F::new(x, y));
for segment in &shape.outline {
let Point2 { x, y } = segment.to.as_f32();
match segment.ctrl {
Some(ctrl) => {
let Point2 { x: ctrl_x, y: ctrl_y } = ctrl.as_f32();
contour.push_quadratic(
Vector2F::new(ctrl_x, ctrl_y),
Vector2F::new(x, y)
);
}
None => {
contour.push_endpoint(Vector2F::new(x, y));
},
}
}
if shape.is_closed() {
// NOTE: I'm not sure if this really does anything in this context,
// since all our closed shapes already have coincident start and end points.
contour.close();
}
path.push_contour(contour);
}
if let PaintOrLine::Line(line) = style_layer.kind() {
let mut stroke_to_fill = OutlineStrokeToFill::new(&path, StrokeStyle {
line_width: line.width.as_f32(),
line_cap: line.cap,
line_join: line.join,
});
stroke_to_fill.offset();
path = stroke_to_fill.into_outline();
}
scene.push_path(PathObject::new(
path,
paint_id,
String::new()
));
}
}
}
}

615
flash/src/shapes.rs Normal file
View File

@ -0,0 +1,615 @@
use pathfinder_renderer::paint::Paint;
use pathfinder_geometry::stroke::{LineJoin, LineCap};
use crate::{Twips, Point2};
use std::mem;
use std::cmp::Ordering;
use swf_tree::{
FillStyle,
StraightSRgba8,
LineStyle,
fill_styles,
JoinStyle,
CapStyle,
join_styles,
ShapeRecord,
shape_records,
Vector2D
};
use pathfinder_geometry::color::ColorU;
use swf_tree::tags::DefineShape;
#[derive(Clone, Copy, Debug)]
pub(crate) struct LineSegment {
pub(crate) from: Point2<Twips>,
pub(crate) to: Point2<Twips>,
pub(crate) ctrl: Option<Point2<Twips>>,
}
impl LineSegment {
fn reverse(&mut self) {
let tmp = self.from;
self.from = self.to;
self.to = tmp;
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub(crate) enum LineDirection {
Left,
Right,
}
impl LineDirection {
fn reverse(&mut self) {
*self = match self {
LineDirection::Right => LineDirection::Left,
LineDirection::Left => LineDirection::Right
};
}
}
#[derive(Clone, Debug)]
pub(crate) struct Shape {
pub(crate) outline: Vec<LineSegment>, // Could be Vec<(start, end)>
direction: LineDirection,
reversed: bool,
}
impl Shape {
pub fn new_with_direction(direction: LineDirection) -> Shape {
Shape {
direction,
outline: Vec::new(),
reversed: false,
}
}
fn prepend_shape(&mut self, shape: &mut Shape) {
shape.append_shape(&self);
mem::swap(&mut self.outline, &mut shape.outline);
}
fn append_shape(&mut self, shape: &Shape) {
self.outline.extend_from_slice(&shape.outline);
}
fn add_line_segment(&mut self, segment: LineSegment) {
self.outline.push(segment);
}
#[inline]
fn len(&self) -> usize {
self.outline.len()
}
#[inline]
fn first(&self) -> &LineSegment {
&self.outline.first().unwrap()
}
#[inline]
fn last(&self) -> &LineSegment {
&self.outline.last().unwrap()
}
#[inline]
fn comes_before(&self, other: &Shape) -> bool {
self.last().to == other.first().from
}
#[inline]
fn comes_after(&self, other: &Shape) -> bool {
self.first().from == other.last().to
}
#[inline]
pub(crate) fn is_closed(&self) -> bool {
self.len() > 1 && self.comes_after(self)
}
fn reverse(&mut self) {
self.reversed = !self.reversed;
self.direction.reverse();
for segment in &mut self.outline {
segment.reverse();
}
self.outline.reverse();
}
}
pub(crate) struct SwfLineStyle {
color: Paint,
pub(crate) width: Twips,
pub(crate) join: LineJoin,
pub(crate) cap: LineCap,
}
pub(crate) enum PaintOrLine {
Paint(Paint),
Line(SwfLineStyle),
}
pub(crate) struct StyleLayer {
fill: PaintOrLine,
// TODO(jon): Maybe shapes are actually slices into a single buffer, then we don't
// need to realloc anything, we're just shuffling shapes around?
shapes: Vec<Shape>,
}
impl StyleLayer {
pub(crate) fn kind(&self) -> &PaintOrLine {
&self.fill
}
fn is_fill(&self) -> bool {
match &self.fill {
PaintOrLine::Paint(_) => true,
PaintOrLine::Line(_) => false,
}
}
pub(crate) fn fill(&self) -> Paint {
match &self.fill {
PaintOrLine::Paint(paint) => *paint,
PaintOrLine::Line(line) => line.color,
}
}
fn push_new_shape(&mut self, direction: LineDirection) {
if let Some(prev_shape) = self.shapes.last_mut() {
// Check that the previous shape was actually used, otherwise reuse it.
if prev_shape.len() != 0 {
self.shapes.push(Shape::new_with_direction(direction))
} else {
prev_shape.direction = direction;
}
} else {
self.shapes.push(Shape::new_with_direction(direction))
}
}
pub(crate) fn shapes(&self) -> &Vec<Shape> {
&self.shapes
}
fn shapes_mut(&mut self) -> &mut Vec<Shape> {
&mut self.shapes
}
fn current_shape_mut(&mut self) -> &mut Shape {
self.shapes.last_mut().unwrap()
}
fn consolidate_edges(&mut self) {
// Reverse left fill shape fragments in place.
{
self.shapes
.iter_mut()
.filter(|frag| frag.direction == LineDirection::Left)
.for_each(|frag| frag.reverse());
}
// Sort shapes into [closed...open]
if self.is_fill() {
// I think sorting is only necessary when we want to have closed shapes,
// lines don't really need this?
self.shapes.sort_unstable_by(|a, b| {
match (a.is_closed(), b.is_closed()) {
(true, true) | (false, false) => Ordering::Equal,
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
}
});
}
// A cursor at the index of the first unclosed shape, if any.
let first_open_index = self.shapes
.iter()
.position(|frag| !frag.is_closed());
if let Some(first_open_index) = first_open_index {
if self.shapes.len() - first_open_index >= 2 {
// TODO(jon): This might be sped up by doing it in a way that we don't have
// to allocate more vecs?
// Also, maybe avoid path reversal, and just flag the path as reversed and iterate it
// backwards.
let unmatched_pieces = find_matches(first_open_index, &mut self.shapes, false);
if let Some(mut unmatched_pieces) = unmatched_pieces {
if self.is_fill() {
// If they didn't match before, they're probably parts of inner shapes
// and should be reversed again so they have correct winding
let unclosed = find_matches(0, &mut unmatched_pieces, true);
// If it's a shape we should always be able to close it.
debug_assert!(unclosed.is_none());
}
for dropped in &mut unmatched_pieces {
dropped.reverse();
}
self.shapes.extend_from_slice(&unmatched_pieces);
}
// FIXME(jon): Sometimes we don't get the correct winding of internal closed shapes,
// need to figure out why this happens.
}
}
}
}
fn get_new_styles<'a>(
fills: &'a Vec<FillStyle>,
lines: &'a Vec<LineStyle>
) -> impl Iterator<Item=PaintOrLine> + 'a {
// This enforces the order that fills and line groupings are added in.
// Fills always come first.
fills.iter().filter_map(|fill_style| {
match fill_style {
FillStyle::Solid(
fill_styles::Solid {
color: StraightSRgba8 {
r,
g,
b,
a
}
}
) => {
Some(PaintOrLine::Paint(Paint {
color: ColorU {
r: *r,
g: *g,
b: *b,
a: *a
}
}))
},
_ => unimplemented!("Unimplemented fill style")
}
}).chain(
lines.iter().filter_map(|LineStyle {
width,
fill,
join,
start_cap,
end_cap: _,
/*
TODO(jon): Handle these cases?
pub no_h_scale: bool,
pub no_v_scale: bool,
pub no_close: bool,
pub pixel_hinting: bool,
*/
..
}| {
if let FillStyle::Solid(fill_styles::Solid {
color: StraightSRgba8 {
r,
g,
b,
a
}
}) = fill {
// NOTE: PathFinder doesn't support different cap styles for start and end of
// strokes, so lets assume that they're always the same for the inputs we care about.
// Alternately, we split a line in two with a diff cap style for each.
// assert_eq!(start_cap, end_cap);
Some(PaintOrLine::Line(SwfLineStyle {
width: Twips(*width as i32),
color: Paint { color: ColorU { r: *r, g: *g, b: *b, a: *a } },
join: match join {
JoinStyle::Bevel => LineJoin::Bevel,
JoinStyle::Round => LineJoin::Round,
JoinStyle::Miter(join_styles::Miter { limit }) => {
LineJoin::Miter(*limit as f32)
},
},
cap: match start_cap {
CapStyle::None => LineCap::Butt,
CapStyle::Square => LineCap::Square,
CapStyle::Round => LineCap::Round,
},
}))
} else {
unimplemented!("unimplemented line fill style");
}
})
)
}
pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
let DefineShape {
shape,
// id,
// has_fill_winding, NOTE(jon): Could be important for some inputs?
// has_non_scaling_strokes,
// has_scaling_strokes,
..
} = shape;
let mut graphic = GraphicLayers::new();
let mut current_line_style = None;
let mut current_left_fill = None;
let mut current_right_fill = None;
let mut prev_pos = None;
let mut some_fill_set = false;
let mut both_fills_set;
let mut both_fills_same = false;
let mut both_fills_set_and_same = false;
// Create style groups for initially specified fills and lines.
for fills_or_line in get_new_styles(&shape.initial_styles.fill, &shape.initial_styles.line) {
match fills_or_line {
PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill),
PaintOrLine::Line(line) => graphic.begin_line_style(line),
}
}
for record in &shape.records {
match record {
ShapeRecord::StyleChange(
shape_records::StyleChange {
move_to,
new_styles,
line_style,
left_fill,
right_fill,
}
) => {
// Start a whole new style grouping.
if let Some(new_style) = new_styles {
// Consolidate current style grouping and begin a new one.
graphic.end_style_group();
graphic.begin_style_group();
for fills_or_line in get_new_styles(&new_style.fill, &new_style.line) {
match fills_or_line {
PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill),
PaintOrLine::Line(line) => graphic.begin_line_style(line),
}
}
}
// If there's a change in right fill
if let Some(fill_id) = right_fill {
if *fill_id == 0 {
current_right_fill = None;
} else {
current_right_fill = Some(*fill_id);
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
// If there's a change in left fill
if let Some(fill_id) = left_fill {
if *fill_id == 0 {
current_left_fill = None;
} else {
current_left_fill = Some(*fill_id);
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(LineDirection::Left);
}
}
some_fill_set = current_left_fill.is_some() || current_right_fill.is_some();
both_fills_set = current_left_fill.is_some() && current_right_fill.is_some();
both_fills_same = current_left_fill == current_right_fill;
both_fills_set_and_same = both_fills_set && both_fills_same;
// If there's a change in line style
if let Some(style_id) = line_style {
if *style_id == 0 {
current_line_style = None;
} else {
current_line_style = Some(*style_id);
graphic
.with_line_style_mut(*style_id)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
// Move to, start new shape fragments with the current styles.
if let Some(Vector2D { x, y }) = move_to {
let to: Point2<Twips> = Point2 { x: Twips(*x), y: Twips(*y) };
prev_pos = Some(to);
// If we didn't start a new shape for the current fill due to a fill
// style change earlier, we definitely want to start a new shape now,
// since each move_to command indicates a new shape fragment.
if let Some(current_right_fill) = current_right_fill {
graphic
.with_fill_style_mut(current_right_fill)
.unwrap()
.push_new_shape(LineDirection::Right);
}
if let Some(current_left_fill) = current_left_fill {
graphic
.with_fill_style_mut(current_left_fill)
.unwrap()
.push_new_shape(LineDirection::Left);
}
if let Some(current_line_style) = current_line_style {
// TODO(jon): Does the direction of this line depend on the current
// fill directions?
graphic
.with_line_style_mut(current_line_style)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
},
ShapeRecord::Edge(
shape_records::Edge {
delta,
control_delta,
}
) => {
let from = prev_pos.unwrap();
let to = Point2 {
x: from.x + Twips(delta.x),
y: from.y + Twips(delta.y)
};
prev_pos = Some(to);
let new_segment = LineSegment {
from,
to,
ctrl: control_delta.map(|Vector2D { x, y }| {
Point2 {
x: from.x + Twips(x),
y: from.y + Twips(y),
}
}),
};
if some_fill_set && !both_fills_same {
for fill_id in [
current_right_fill,
current_left_fill
].iter() {
if let Some(fill_id) = fill_id {
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.current_shape_mut()
.add_line_segment(new_segment);
}
}
} else if both_fills_set_and_same {
for (fill_id, direction) in [
(current_right_fill, LineDirection::Right),
(current_left_fill, LineDirection::Left)
].iter() {
// NOTE: If both left and right fill are set the same,
// then we don't record the edge as part of the current shape;
// it's will just be an internal stroke inside an otherwise solid
// shape, and recording these edges as part of the shape means that
// we can't determine the closed shape outline later.
if let Some(fill_id) = fill_id {
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(*direction);
}
}
}
if let Some(current_line_style) = current_line_style {
graphic
.with_line_style_mut(current_line_style)
.unwrap()
.current_shape_mut()
.add_line_segment(new_segment);
}
}
}
}
// NOTE: Consolidate current group of styles, joining edges of shapes/strokes where
// possible and forming closed shapes. In swf, all filled shapes should always be closed,
// so there will always be a solution for joining shape line segments together so that
// the start point and end point are coincident.
graphic.end_style_group();
graphic
}
fn find_matches(
mut first_open_index: usize,
shapes: &mut Vec<Shape>,
reverse: bool
) -> Option<Vec<Shape>> {
let mut dropped_pieces = None;
while first_open_index < shapes.len() {
// Take the last unclosed value, and try to join it onto
// one of the other unclosed values.
let mut last = shapes.pop().unwrap();
if reverse {
last.reverse();
}
let mut found_match = false;
for i in first_open_index..shapes.len() {
let fragment = &mut shapes[i];
if last.comes_after(fragment) {
// NOTE(jon): We do realloc quite a bit here, I wonder if it's worth trying
// to avoid that? Could do it with another level of indirection, where an outline
// is a list of fragments.
// println!("app ({}, {})", last.reversed, fragment.reversed);
fragment.append_shape(&last);
found_match = true;
} else if last.comes_before(fragment) {
// println!("pre ({}, {})", last.reversed, fragment.reversed);
fragment.prepend_shape(&mut last);
found_match = true;
}
if found_match {
if fragment.is_closed() {
// Move the shape that was just closed to the left side of the current slice,
// and advance the cursor.
shapes.swap(first_open_index, i);
first_open_index += 1;
}
break;
}
}
if !found_match {
// Have we tried matching a reversed version of this segment?
// move last back onto the array, it will never be closed, presumably because
// it's a set of line segments rather than a shape that needs to be closed.
let dropped_pieces: &mut Vec<Shape> = dropped_pieces.get_or_insert(Vec::new());
dropped_pieces.push(last);
}
}
dropped_pieces
}
pub(crate) struct GraphicLayers {
style_layers: Vec<StyleLayer>,
base_layer_offset: usize,
stroke_layer_offset: Option<usize>,
}
impl GraphicLayers {
fn new() -> GraphicLayers {
GraphicLayers { style_layers: Vec::new(), stroke_layer_offset: None, base_layer_offset: 0 }
}
fn begin_style_group(&mut self) {
self.stroke_layer_offset = None;
self.base_layer_offset = self.style_layers.len();
}
fn begin_fill_style(&mut self, fill: Paint) {
self.style_layers.push(StyleLayer { fill: PaintOrLine::Paint(fill), shapes: Vec::new() })
}
fn begin_line_style(&mut self, line: SwfLineStyle) {
if self.stroke_layer_offset.is_none() {
self.stroke_layer_offset = Some(self.style_layers.len());
}
self.style_layers.push(StyleLayer { fill: PaintOrLine::Line(line), shapes: Vec::new() })
}
fn with_fill_style_mut(&mut self, fill_id: usize) -> Option<&mut StyleLayer> {
self.style_layers.get_mut(self.base_layer_offset + fill_id - 1)
}
fn with_line_style_mut(&mut self, line_id: usize) -> Option<&mut StyleLayer> {
self.style_layers.get_mut((self.stroke_layer_offset.unwrap() + line_id) - 1)
}
pub(crate) fn layers(&self) -> &Vec<StyleLayer> {
&self.style_layers
}
fn end_style_group(&mut self) {
for style_layer in &mut self.style_layers[self.base_layer_offset..] {
// There can be an unused style group at the end of each layer, which we should remove.
if let Some(last) = style_layer.shapes().last() {
if last.len() == 0 {
style_layer.shapes_mut().pop();
}
}
style_layer.consolidate_edges();
}
}
}

32
flash/src/timeline.rs Normal file
View File

@ -0,0 +1,32 @@
struct PlacementInfo {
symbol_id: u32,
translate_x: Twips,
translate_y: Twips,
}
struct Timeline(Vec<Frame>);
impl Timeline {
fn first(&self) -> &Frame {
&self.0[0]
}
fn last(&self) -> &Frame {
&self.0[self.0.len() - 1]
}
fn first_mut(&mut self) -> &mut Frame {
&mut self.0[0]
}
fn last_mut(&mut self) -> &mut Frame {
let last = self.0.len() - 1;
&mut self.0[last]
}
}
struct Frame {
duration_frames_initial: u16,
duration_remaining_frames: u16,
placements: Vec<PlacementInfo>
}