Use resvg instead of hand-rolling SVG parsing

This commit is contained in:
Patrick Walton 2019-01-03 13:57:14 -08:00
parent bc25f087a6
commit 7af83c9ddf
3 changed files with 234 additions and 287 deletions

116
Cargo.lock generated
View File

@ -272,6 +272,14 @@ dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crc32fast"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-deque"
version = "0.2.0"
@ -338,14 +346,6 @@ name = "either"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encoding_rs"
version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.5.13"
@ -749,6 +749,16 @@ name = "libc"
version = "0.2.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libflate"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "linked-hash-map"
version = "0.4.2"
@ -1075,17 +1085,6 @@ name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quick-xml"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quickcheck"
version = "0.7.2"
@ -1159,6 +1158,11 @@ dependencies = [
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rctree"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_syscall"
version = "0.1.40"
@ -1250,6 +1254,14 @@ dependencies = [
"serde_json 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "roxmltree"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rsvg"
version = "0.3.0"
@ -1377,11 +1389,21 @@ dependencies = [
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "simplecss"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.6.5"
@ -1400,15 +1422,25 @@ name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "svgdom"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "svgtypes"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)",
"xmlparser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1489,11 +1521,11 @@ dependencies = [
"lyon_geom 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_path_utils 0.2.0",
"quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"svgtypes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1550,6 +1582,11 @@ name = "unicode-normalization"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-segmentation"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
@ -1583,6 +1620,20 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "usvg"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_geom 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rctree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "1.0.1"
@ -1656,7 +1707,7 @@ dependencies = [
[[package]]
name = "xmlparser"
version = "0.6.1"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1702,6 +1753,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9"
"checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
@ -1709,7 +1761,6 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum dirs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f679c09c1cf5428702cc10f6846c56e4e23420d3a88bcc9335b17c630a7b710b"
"checksum dwrote 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031b304062005e27cc3a7e2be0880e176f468418a89d91a45ba72e82a8a9cfd5"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1a8fa54e6689eb2549c4efed8d00d7f3b2b994a064555b0e8df4ae3764bcc4be"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f"
"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
@ -1752,6 +1803,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b"
"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
@ -1785,7 +1837,6 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b"
"checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
"checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
@ -1794,6 +1845,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa"
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
"checksum rctree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1817e0f0056f95bce0d6ab1a5be62ca24bd756b5547c20637ef47cc9a2065f4b"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341"
@ -1802,6 +1854,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum rocket 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc32be1d093e7b2f9718983318c6bf5a14f43d7ea01a0b5143c3450c90725b9"
"checksum rocket_codegen 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc94e7781a8bc502f3614521ae94b562f209c7537671cb6169cbbe9dbcc6c5e"
"checksum rocket_contrib 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bae00c367de4599157febc585431c7c647c5f0ffa8fa0e9e875edbbb0bd929"
"checksum roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02660467d0c2da1b6276042501aee6e15ec5b8ff59423243f185b294cd53acf3"
"checksum rsvg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2032b49fe075a3b921573286f7debe130aebdac6cb37fb197f9b517a4237024"
"checksum rsvg-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ceca0b663cfddd09062d7e3fe0a729765d1e61bbbbb6a31d5e23d141ff0db38"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
@ -1817,11 +1870,14 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
"checksum servo-fontconfig-sys 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa080856db55f188aaf36f01cae8c03448a6056552adb77d461179e44e1a14"
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
"checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d"
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum svgtypes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7da116a3aedb07023f8399e126d0467bd9629d3a235f339eb7986f779a07c9"
"checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d"
"checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9056ebe7f2d6a38bc63171816fd1d3430da5a43896de21676dc5c0a4b8274a11"
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
@ -1837,11 +1893,13 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae"
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ebf4d5244ba2e8305caf9de7949377794ecdea5a9e3c84fc5610d78d21f5ee"
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
@ -1853,5 +1911,5 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
"checksum xmlparser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea75f29e9916cc12af3af844a59d2d2ba1ca33aa956e9a162240dc7124cc72bb"
"checksum xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d78a7f29bb57edf63321d545d84f99360df71df36929a090bc067e1bcb65e34d"
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"

View File

@ -13,9 +13,9 @@ fixedbitset = "0.1"
jemallocator = "0.1"
lyon_geom = "0.12"
lyon_path = "0.12"
quick-xml = "0.12"
rayon = "1.0"
svgtypes = "0.2"
svgtypes = "0.3"
usvg = "0.4"
[dependencies.pathfinder_path_utils]
path = "../../path-utils"

View File

@ -1,6 +1,6 @@
// pathfinder/utils/tile-svg/main.rs
//
// Copyright © 2018 The Pathfinder Project Developers.
// 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
@ -27,22 +27,19 @@ use lyon_geom::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};
use lyon_path::PathEvent;
use lyon_path::iterator::PathIter;
use pathfinder_path_utils::stroke::{StrokeStyle, StrokeToFillIter};
use quick_xml::Reader;
use quick_xml::events::{BytesStart, Event};
use rayon::ThreadPoolBuilder;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};
use std::fs::File;
use std::io::{self, BufReader, BufWriter, Write};
use std::io::{self, BufWriter, Write};
use std::mem;
use std::ops::Range;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::path::PathBuf;
use std::time::Instant;
use std::u16;
use svgtypes::{Color as SvgColor, PathParser, PathSegment as SvgPathSegment, TransformListParser};
use svgtypes::{TransformListToken};
use svgtypes::Color as SvgColor;
use usvg::{Node, NodeExt, NodeKind, Options as UsvgOptions, Paint, PathSegment as UsvgPathSegment};
use usvg::{Rect as UsvgRect, Transform as UsvgTransform, Tree};
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
@ -89,7 +86,9 @@ fn main() {
}
thread_pool_builder.build_global().unwrap();
let scene = Scene::from_path(&input_path);
// Build scene.
let usvg = Tree::from_file(&input_path, &UsvgOptions::default()).unwrap();
let scene = Scene::from_tree(usvg);
println!("Scene bounds: {:?} View box: {:?}", scene.bounds, scene.view_box);
//println!("{:#?}", scene.objects[0]);
@ -154,29 +153,7 @@ pub enum PathObjectKind {
#[derive(Debug)]
struct ComputedStyle {
fill_color: Option<SvgColor>,
stroke_width: f32,
stroke_color: Option<SvgColor>,
transform: Transform2D<f32>,
}
#[derive(Default)]
struct GroupStyle {
fill_color: Option<SvgColor>,
stroke_width: Option<f32>,
stroke_color: Option<SvgColor>,
transform: Option<Transform2D<f32>>,
}
impl ComputedStyle {
fn new() -> ComputedStyle {
ComputedStyle {
fill_color: None,
stroke_width: 1.0,
stroke_color: None,
transform: Transform2D::identity(),
}
}
color: Option<SvgColor>,
}
#[derive(Clone, Copy, PartialEq, Debug)]
@ -187,17 +164,76 @@ impl Scene {
Scene { objects: vec![], styles: vec![], bounds: Rect::zero(), view_box: Rect::zero() }
}
fn from_path(path: &Path) -> Scene {
let mut reader = Reader::from_file(&path).unwrap();
fn from_tree(tree: Tree) -> Scene {
let global_transform = Transform2D::create_scale(SCALE_FACTOR, SCALE_FACTOR);
let mut xml_buffer = vec![];
let mut group_styles = vec![];
let mut style = None;
let mut scene = Scene::new();
let root = &tree.root();
match *root.borrow() {
NodeKind::Svg(ref svg) => {
scene.view_box = usvg_rect_to_euclid_rect(&svg.view_box.rect);
for kid in root.children() {
process_node(&mut scene, &kid, &global_transform);
}
}
_ => unreachable!(),
};
return scene;
fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2D<f32>) {
let node_transform = usvg_transform_to_euclid_transform_2d(&node.transform());
let transform = transform.pre_mul(&node_transform);
match *node.borrow() {
NodeKind::Group(_) => {
for kid in node.children() {
process_node(scene, &kid, &transform)
}
}
NodeKind::Path(ref path) => {
if let Some(ref fill) = path.fill {
let style = scene.push_paint(&fill.paint);
let path = UsvgPathToPathEvents::new(path.segments.iter().cloned());
let path = PathTransformingIter::new(path, &transform);
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_path_events(path);
scene.bounds = scene.bounds.union(&outline.bounds);
scene.objects.push(PathObject::new(outline,
style,
node.id().to_string(),
PathObjectKind::Fill));
}
if let Some(ref stroke) = path.stroke {
let style = scene.push_paint(&stroke.paint);
let stroke_width = f32::max(stroke.width.value() as f32,
HAIRLINE_STROKE_WIDTH);
let path = UsvgPathToPathEvents::new(path.segments.iter().cloned());
let path = PathIter::new(path);
let path = StrokeToFillIter::new(path, StrokeStyle::new(stroke_width));
let path = PathTransformingIter::new(path, &transform);
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_path_events(path);
scene.bounds = scene.bounds.union(&outline.bounds);
scene.objects.push(PathObject::new(outline,
style,
node.id().to_string(),
PathObjectKind::Stroke));
}
}
_ => {
// TODO(pcwalton): Handle these by punting to WebRender.
}
}
}
/*
loop {
match reader.read_event(&mut xml_buffer) {
Ok(Event::Start(ref event)) |
@ -255,91 +291,18 @@ impl Scene {
}
return scene;
*/
}
fn push_group_style(&mut self,
reader: &mut Reader<BufReader<File>>,
event: &BytesStart,
group_styles: &mut Vec<GroupStyle>,
style: &mut Option<StyleId>) {
let mut group_style = GroupStyle::default();
let attributes = event.attributes();
for attribute in attributes {
let attribute = attribute.unwrap();
match attribute.key {
b"fill" => {
let value = reader.decode(&attribute.value);
if let Ok(color) = SvgColor::from_str(&value) {
group_style.fill_color = Some(color);
}
}
b"stroke" => {
let value = reader.decode(&attribute.value);
if let Ok(color) = SvgColor::from_str(&value) {
group_style.stroke_color = Some(color)
}
}
b"transform" => {
let value = reader.decode(&attribute.value);
let mut current_transform = Transform2D::identity();
let transform_list_parser = TransformListParser::from(&*value);
for transform in transform_list_parser {
match transform {
Ok(TransformListToken::Matrix { a, b, c, d, e, f }) => {
let transform: Transform2D<f32> =
Transform2D::row_major(a, b, c, d, e, f).cast();
current_transform = current_transform.pre_mul(&transform)
}
Ok(TransformListToken::Scale { sx, sy }) => {
current_transform =
current_transform.pre_scale(sx as f32, sy as f32)
}
_ => {
eprintln!("warning: unknown transform list token");
}
}
}
group_style.transform = Some(current_transform);
}
b"stroke-width" => {
if let Ok(width) = reader.decode(&attribute.value).parse() {
let width: f32 = width;
//group_style.stroke_width = Some(1.0);
group_style.stroke_width = Some(width);
}
}
_ => {}
}
}
group_styles.push(group_style);
*style = None;
}
fn ensure_style(&mut self, current_style: &mut Option<StyleId>, group_styles: &[GroupStyle])
-> StyleId {
if let Some(current_style) = *current_style {
return current_style
}
let mut computed_style = ComputedStyle::new();
for group_style in group_styles {
if let Some(fill_color) = group_style.fill_color {
computed_style.fill_color = Some(fill_color)
}
if let Some(stroke_width) = group_style.stroke_width {
computed_style.stroke_width = stroke_width
}
if let Some(stroke_color) = group_style.stroke_color {
computed_style.stroke_color = Some(stroke_color)
}
if let Some(transform) = group_style.transform {
computed_style.transform = computed_style.transform.pre_mul(&transform)
}
}
fn push_paint(&mut self, paint: &Paint) -> StyleId {
let id = StyleId(self.styles.len() as u32);
self.styles.push(computed_style);
self.styles.push(ComputedStyle {
color: match *paint {
Paint::Color(color) => Some(color),
Paint::Link(..) => None,
}
});
id
}
@ -350,15 +313,8 @@ impl Scene {
fn build_shader(&self, object_index: u16) -> ObjectShader {
let object = &self.objects[object_index as usize];
let style = self.get_style(object.style);
let fill_color = match object.kind {
PathObjectKind::Fill => style.fill_color,
PathObjectKind::Stroke => style.stroke_color,
};
let fill_color = match fill_color {
None => ColorU::black(),
Some(fill_color) => ColorU::from_svg_color(fill_color),
};
ObjectShader { fill_color }
let color = style.color.map(ColorU::from_svg_color).unwrap_or(ColorU::black());
ObjectShader { fill_color: color }
}
// This function exists to make profiling easier.
@ -384,6 +340,7 @@ impl Scene {
}).collect()
}
/*
fn push_svg_path(&mut self, value: &str, style: StyleId, name: String) {
let global_transform = Transform2D::create_scale(SCALE_FACTOR, SCALE_FACTOR);
let transform = global_transform.pre_mul(&self.get_style(style).transform);
@ -394,7 +351,7 @@ impl Scene {
let path = SvgPathToPathEvents::new(&mut path_parser);
let path = PathTransformingIter::new(path, &transform);
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_path_events(path, computed_style);
let outline = Outline::from_path_events(path);
self.bounds = self.bounds.union(&outline.bounds);
self.objects.push(PathObject::new(outline, style, name.clone(), PathObjectKind::Fill));
@ -410,12 +367,13 @@ impl Scene {
let path = StrokeToFillIter::new(path, StrokeStyle::new(stroke_width));
let path = PathTransformingIter::new(path, &transform);
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_path_events(path, computed_style);
let outline = Outline::from_path_events(path);
self.bounds = self.bounds.union(&outline.bounds);
self.objects.push(PathObject::new(outline, style, name, PathObjectKind::Stroke));
}
}
*/
}
impl PathObject {
@ -453,8 +411,7 @@ impl Outline {
}
// NB: Assumes the path has already been transformed.
fn from_path_events<I>(path_events: I, style: &ComputedStyle) -> Outline
where I: Iterator<Item = PathEvent> {
fn from_path_events<I>(path_events: I) -> Outline where I: Iterator<Item = PathEvent> {
let mut outline = Outline::new();
let mut current_contour = Contour::new();
let mut bounding_points = None;
@ -925,17 +882,6 @@ impl Segment {
fn is_none(&self) -> bool {
!self.flags.contains(SegmentFlags::HAS_ENDPOINTS)
}
fn min_x(&self) -> f32 { f32::min(self.from.x, self.to.x) }
fn max_x(&self) -> f32 { f32::max(self.from.x, self.to.x) }
fn winding(&self) -> i32 {
match self.from.x.partial_cmp(&self.to.x) {
Some(Ordering::Less) => -1,
Some(Ordering::Greater) => 1,
Some(Ordering::Equal) | None => 0,
}
}
}
bitflags! {
@ -1016,8 +962,6 @@ impl<'o> Tiler<'o> {
}
fn process_old_active_edges(&mut self, tile_y: i16) {
let tile_origin_y = tile_y as f32 * TILE_HEIGHT;
let mut current_tile_x = self.built_object.tile_rect.origin.x;
let mut current_subtile_x = 0.0;
let mut current_winding = 0;
@ -1431,18 +1375,6 @@ impl BuiltObject {
const MAX_U12: f32 = 16.0 - 1.0 / 256.0;
/*
println!("from={:?} to={:?}", from, to);
debug_assert!(from.x > -EPSILON);
debug_assert!(from.x < TILE_WIDTH + EPSILON);
debug_assert!(to.x > -EPSILON);
debug_assert!(to.x < TILE_WIDTH + EPSILON);
debug_assert!(from.y > -EPSILON);
debug_assert!(from.y < TILE_HEIGHT + EPSILON);
debug_assert!(to.y > -EPSILON);
debug_assert!(to.y < TILE_HEIGHT + EPSILON);
*/
let from_px = Point2DU4::new(from.x as u8, from.y as u8);
let to_px = Point2DU4::new(to.x as u8, to.y as u8);
let from_subpx = Point2D::new((from.x.fract() * 256.0) as u8,
@ -1456,9 +1388,6 @@ impl BuiltObject {
});
self.solid_tiles.set(tile_index as usize, false);
// FIXME(pcwalton): This is really sloppy!
const EPSILON: f32 = 0.25;
}
fn add_active_fill(&mut self,
@ -1614,107 +1543,45 @@ fn round_rect_out_to_tile_bounds(rect: &Rect<f32>) -> Rect<i16> {
Rect::new(tile_origin, tile_size)
}
// SVG stuff
// USVG stuff
struct SvgPathToPathEvents<'a, I> where I: Iterator<Item = SvgPathSegment> {
iter: &'a mut I,
last_endpoint: Point2D<f32>,
last_ctrl_point: Option<Point2D<f32>>,
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> Rect<f32> {
Rect::new(Point2D::new(rect.x, rect.y), Size2D::new(rect.width, rect.height)).to_f32()
}
impl<'a, I> SvgPathToPathEvents<'a, I> where I: Iterator<Item = SvgPathSegment> {
fn new(iter: &'a mut I) -> SvgPathToPathEvents<'a, I> {
SvgPathToPathEvents { iter, last_endpoint: Point2D::zero(), last_ctrl_point: None }
fn usvg_transform_to_euclid_transform_2d(transform: &UsvgTransform) -> Transform2D<f32> {
Transform2D::row_major(transform.a as f32, transform.b as f32,
transform.c as f32, transform.d as f32,
transform.e as f32, transform.f as f32)
}
struct UsvgPathToPathEvents<I> where I: Iterator<Item = UsvgPathSegment> {
iter: I,
}
impl<I> UsvgPathToPathEvents<I> where I: Iterator<Item = UsvgPathSegment> {
fn new(iter: I) -> UsvgPathToPathEvents<I> {
UsvgPathToPathEvents { iter }
}
}
impl<'a, I> Iterator for SvgPathToPathEvents<'a, I> where I: Iterator<Item = SvgPathSegment> {
impl<I> Iterator for UsvgPathToPathEvents<I> where I: Iterator<Item = UsvgPathSegment> {
type Item = PathEvent;
fn next(&mut self) -> Option<PathEvent> {
return match self.iter.next() {
None => None,
Some(SvgPathSegment::MoveTo { abs, x, y }) => {
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
self.last_ctrl_point = None;
Some(PathEvent::MoveTo(to))
match self.iter.next()? {
UsvgPathSegment::MoveTo { x, y } => {
Some(PathEvent::MoveTo(Point2D::new(x, y).to_f32()))
}
Some(SvgPathSegment::LineTo { abs, x, y }) => {
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
self.last_ctrl_point = None;
Some(PathEvent::LineTo(to))
UsvgPathSegment::LineTo { x, y } => {
Some(PathEvent::LineTo(Point2D::new(x, y).to_f32()))
}
Some(SvgPathSegment::HorizontalLineTo { abs, x }) => {
let to = compute_point(x, 0.0, abs, &self.last_endpoint);
self.last_endpoint = to;
self.last_ctrl_point = None;
Some(PathEvent::LineTo(to))
}
Some(SvgPathSegment::VerticalLineTo { abs, y }) => {
let to = compute_point(0.0, y, abs, &self.last_endpoint);
self.last_endpoint = to;
self.last_ctrl_point = None;
Some(PathEvent::LineTo(to))
}
Some(SvgPathSegment::Quadratic { abs, x1, y1, x, y }) => {
let ctrl = compute_point(x1, y1, abs, &self.last_endpoint);
self.last_ctrl_point = Some(ctrl);
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
Some(PathEvent::QuadraticTo(ctrl, to))
}
Some(SvgPathSegment::SmoothQuadratic { abs, x, y }) => {
let ctrl = reflect_point(&self.last_endpoint, &self.last_ctrl_point);
self.last_ctrl_point = Some(ctrl);
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
Some(PathEvent::QuadraticTo(ctrl, to))
}
Some(SvgPathSegment::CurveTo { abs, x1, y1, x2, y2, x, y }) => {
let ctrl0 = compute_point(x1, y1, abs, &self.last_endpoint);
let ctrl1 = compute_point(x2, y2, abs, &self.last_endpoint);
self.last_ctrl_point = Some(ctrl1);
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
Some(PathEvent::CubicTo(ctrl0, ctrl1, to))
}
Some(SvgPathSegment::SmoothCurveTo { abs, x2, y2, x, y }) => {
let ctrl0 = reflect_point(&self.last_endpoint, &self.last_ctrl_point);
let ctrl1 = compute_point(x2, y2, abs, &self.last_endpoint);
self.last_ctrl_point = Some(ctrl1);
let to = compute_point(x, y, abs, &self.last_endpoint);
self.last_endpoint = to;
Some(PathEvent::CubicTo(ctrl0, ctrl1, to))
}
Some(SvgPathSegment::ClosePath { abs: _ }) => {
// FIXME(pcwalton): Current endpoint becomes path initial point!
self.last_ctrl_point = None;
Some(PathEvent::Close)
}
Some(SvgPathSegment::EllipticalArc { .. }) => unimplemented!("arcs"),
};
fn compute_point(x: f64, y: f64, abs: bool, last_endpoint: &Point2D<f32>)
-> Point2D<f32> {
let point = Point2D::new(x, y).to_f32();
if !abs {
*last_endpoint + point.to_vector()
} else {
point
}
}
fn reflect_point(last_endpoint: &Point2D<f32>, last_ctrl_point: &Option<Point2D<f32>>)
-> Point2D<f32> {
match *last_ctrl_point {
Some(ref last_ctrl_point) => {
let vector = *last_endpoint - *last_ctrl_point;
*last_endpoint + vector
}
None => *last_endpoint,
UsvgPathSegment::CurveTo { x1, y1, x2, y2, x, y } => {
Some(PathEvent::CubicTo(Point2D::new(x1, y1).to_f32(),
Point2D::new(x2, y2).to_f32(),
Point2D::new(x, y) .to_f32()))
}
UsvgPathSegment::ClosePath => Some(PathEvent::Close),
}
}
}
@ -1785,6 +1652,10 @@ impl<I> Iterator for MonotonicConversionIter<I> where I: Iterator<Item = PathEve
self.last_point = to;
return Some(PathEvent::CubicTo(ctrl0, ctrl1, to))
}
if cubic_segment_is_tiny(&segment) {
self.last_point = to;
return Some(PathEvent::CubicTo(ctrl0, ctrl1, to))
}
// FIXME(pcwalton): O(n^2)!
let mut t = 1.0;
segment.for_each_monotonic_t(|split_t| {
@ -1808,6 +1679,10 @@ impl<I> Iterator for MonotonicConversionIter<I> where I: Iterator<Item = PathEve
self.last_point = to;
return Some(PathEvent::QuadraticTo(ctrl, to))
}
if quadratic_segment_is_tiny(&segment) {
self.last_point = to;
return Some(PathEvent::QuadraticTo(ctrl, to))
}
// FIXME(pcwalton): O(n^2)!
let mut t = 1.0;
segment.for_each_monotonic_t(|split_t| {
@ -2040,9 +1915,6 @@ struct Point2DU4(pub u8);
impl Point2DU4 {
fn new(x: u8, y: u8) -> Point2DU4 { Point2DU4(x | (y << 4)) }
fn x(self) -> u8 { self.0 & 0xf }
fn y(self) -> u8 { self.0 >> 4 }
}
// Path utilities
@ -2061,7 +1933,6 @@ fn cubic_segment_is_nearly_monotonic(segment: &CubicBezierSegment<f32>) -> bool
const EPSILON: f32 = 0.1;
}
*/
fn cubic_segment_is_nearly_monotonic(segment: &CubicBezierSegment<f32>) -> bool {
let mut t = None;
@ -2077,6 +1948,24 @@ fn cubic_segment_is_nearly_monotonic(segment: &CubicBezierSegment<f32>) -> bool
const EPSILON: f32 = 0.01;
}
*/
const TINY_EPSILON: f32 = 0.1;
fn cubic_segment_is_tiny(segment: &CubicBezierSegment<f32>) -> bool {
let (x0, x1) = segment.fast_bounding_range_x();
let (y0, y1) = segment.fast_bounding_range_y();
let (x_delta, y_delta) = (f32::abs(x0 - x1), f32::abs(y0 - y1));
return x_delta < TINY_EPSILON || y_delta < TINY_EPSILON;
}
fn quadratic_segment_is_tiny(segment: &QuadraticBezierSegment<f32>) -> bool {
let (x0, x1) = segment.fast_bounding_range_x();
let (y0, y1) = segment.fast_bounding_range_y();
let (x_delta, y_delta) = (f32::abs(x0 - x1), f32::abs(y0 - y1));
return x_delta < TINY_EPSILON || y_delta < TINY_EPSILON;
}
// Trivial utilities