Merge branch 'dev' (unicode_support feature)

This commit is contained in:
Stephen Seo 2022-08-01 12:13:22 +09:00
commit 625daa58e3
10 changed files with 985 additions and 160 deletions

393
Cargo.lock generated
View file

@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser 0.15.0",
"owned_ttf_parser 0.15.1",
]
[[package]]
@ -30,6 +30,15 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "alsa"
version = "0.6.0"
@ -114,27 +123,32 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base-x"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc19a4937b4fbd3fe3379793130e42060d10627a360f2127802b10b87e7baf74"
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
[[package]]
name = "bindgen"
version = "0.59.2"
version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5"
dependencies = [
"bitflags",
"cexpr",
"cfg-if 0.1.10",
"clang-sys",
"clap",
"env_logger",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
@ -157,21 +171,21 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "bumpalo"
version = "3.9.1"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "bytecount"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]]
name = "bytemuck"
version = "1.9.1"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835"
[[package]]
name = "byteorder"
@ -181,9 +195,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e"
[[package]]
name = "bzip2"
@ -218,9 +232,9 @@ dependencies = [
[[package]]
name = "camino"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07fd178c5af4d59e83498ef15cf3f154e1a6f9d091270cb86283c65ef44e9ef0"
checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
dependencies = [
"serde",
]
@ -242,7 +256,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
dependencies = [
"camino",
"cargo-platform",
"semver 1.0.9",
"semver 1.0.12",
"serde",
"serde_json",
]
@ -264,11 +278,11 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
"nom 5.1.2",
]
[[package]]
@ -294,13 +308,13 @@ dependencies = [
[[package]]
name = "clang-sys"
version = "1.3.1"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21"
checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
dependencies = [
"glob",
"libc",
"libloading 0.7.3",
"libloading 0.5.2",
]
[[package]]
@ -324,6 +338,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
[[package]]
name = "cmake"
version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a"
dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.24.0"
@ -481,9 +504,9 @@ dependencies = [
[[package]]
name = "coreaudio-sys"
version = "0.2.10"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6"
checksum = "17f73df0f29f4c3c374854f076c47dc018f19acaa63538880dba0937ad4fa8d7"
dependencies = [
"bindgen",
]
@ -524,9 +547,9 @@ dependencies = [
[[package]]
name = "crossbeam"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-channel",
@ -538,9 +561,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.4"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
@ -548,9 +571,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
@ -559,23 +582,23 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.8"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"crossbeam-utils",
"lazy_static",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
@ -583,12 +606,12 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.8"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
dependencies = [
"cfg-if 1.0.0",
"lazy_static",
"once_cell",
]
[[package]]
@ -762,9 +785,22 @@ dependencies = [
[[package]]
name = "either"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "error-chain"
@ -802,23 +838,21 @@ dependencies = [
[[package]]
name = "fastrand"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
[[package]]
name = "flate2"
version = "1.0.23"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
dependencies = [
"cfg-if 1.0.0",
"crc32fast",
"libc",
"miniz_oxide 0.5.1",
"miniz_oxide 0.5.3",
]
[[package]]
@ -832,9 +866,9 @@ dependencies = [
[[package]]
name = "flume"
version = "0.10.12"
version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
"futures-core",
"futures-sink",
@ -864,6 +898,27 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "freetype"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6"
dependencies = [
"freetype-sys",
"libc",
]
[[package]]
name = "freetype-sys"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
dependencies = [
"cmake",
"libc",
"pkg-config",
]
[[package]]
name = "futures-core"
version = "0.3.21"
@ -878,9 +933,9 @@ checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@ -965,9 +1020,9 @@ dependencies = [
[[package]]
name = "gif"
version = "0.11.3"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b"
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
dependencies = [
"color_quant",
"weezl",
@ -1172,6 +1227,15 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549"
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -1197,9 +1261,9 @@ dependencies = [
[[package]]
name = "image"
version = "0.24.2"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212"
checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964"
dependencies = [
"bytemuck",
"byteorder",
@ -1207,12 +1271,11 @@ dependencies = [
"exr",
"gif",
"jpeg-decoder 0.2.6",
"num-iter",
"num-rational 0.4.0",
"num-rational 0.4.1",
"num-traits",
"png 0.17.5",
"scoped_threadpool",
"tiff 0.7.2",
"tiff 0.7.3",
]
[[package]]
@ -1295,9 +1358,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.57"
version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
dependencies = [
"wasm-bindgen",
]
@ -1339,9 +1402,19 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.125"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libloading"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
dependencies = [
"cc",
"winapi",
]
[[package]]
name = "libloading"
@ -1375,9 +1448,9 @@ dependencies = [
[[package]]
name = "linked-hash-map"
version = "0.5.4"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "lock_api"
@ -1420,9 +1493,9 @@ dependencies = [
[[package]]
name = "lyon_geom"
version = "0.17.6"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce99ce77c22bfd8f39a95b9c749dffbfc3e2491ea30c874764c801a8b1485489"
checksum = "71d89ccbdafd83d259403e22061be27bccc3254bba65cdc5303250c4227c8c8e"
dependencies = [
"arrayvec",
"euclid",
@ -1546,9 +1619,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.5.1"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler",
]
@ -1595,10 +1668,12 @@ dependencies = [
[[package]]
name = "mpd_info_screen"
version = "0.2.20"
version = "0.3.0"
dependencies = [
"bindgen",
"freetype",
"ggez",
"image 0.24.2",
"image 0.24.3",
"structopt",
]
@ -1749,6 +1824,16 @@ dependencies = [
"memoffset",
]
[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "nom"
version = "7.1.1"
@ -1813,9 +1898,9 @@ dependencies = [
[[package]]
name = "num-rational"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-integer",
@ -1916,9 +2001,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.10.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "ordered-float"
@ -1949,11 +2034,11 @@ dependencies = [
[[package]]
name = "owned_ttf_parser"
version = "0.15.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d"
checksum = "07ef1a404ae479dd6906f4fa2c88b3c94028f1284beb42a47c183a7c27ee9a3e"
dependencies = [
"ttf-parser 0.15.0",
"ttf-parser 0.15.2",
]
[[package]]
@ -1995,18 +2080,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
dependencies = [
"proc-macro2",
"quote",
@ -2040,7 +2125,7 @@ dependencies = [
"bitflags",
"crc32fast",
"deflate 1.0.0",
"miniz_oxide 0.5.1",
"miniz_oxide 0.5.3",
]
[[package]]
@ -2094,18 +2179,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.38"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "pulldown-cmark"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
dependencies = [
"bitflags",
"memchr",
@ -2113,10 +2198,16 @@ dependencies = [
]
[[package]]
name = "quote"
version = "1.0.18"
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2",
]
@ -2196,9 +2287,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.13"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
@ -2216,18 +2307,20 @@ dependencies = [
[[package]]
name = "regex"
version = "1.5.5"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "remove_dir_all"
@ -2331,9 +2424,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.9"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
dependencies = [
"serde",
]
@ -2346,18 +2439,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.137"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.137"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
dependencies = [
"proc-macro2",
"quote",
@ -2366,9 +2459,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
dependencies = [
"itoa",
"ryu",
@ -2402,9 +2495,9 @@ dependencies = [
[[package]]
name = "shlex"
version = "1.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "sid"
@ -2443,9 +2536,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "smart-default"
@ -2479,9 +2572,9 @@ dependencies = [
[[package]]
name = "spin"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d"
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
dependencies = [
"lock_api",
]
@ -2593,13 +2686,13 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.94"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
@ -2616,6 +2709,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -2667,9 +2769,9 @@ dependencies = [
[[package]]
name = "tiff"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cfada0986f446a770eca461e8c6566cb879682f7d687c8348aa0c857bd52286"
checksum = "7259662e32d1e219321eb309d5f9d898b779769d81b76e762c07c8e5d38fcb65"
dependencies = [
"flate2",
"jpeg-decoder 0.2.6",
@ -2708,9 +2810,9 @@ checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "ttf-parser"
version = "0.15.0"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]]
name = "twox-hash"
@ -2732,6 +2834,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "unicode-ident"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
@ -2744,12 +2852,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "uuid"
version = "0.8.2"
@ -2781,15 +2883,15 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.80"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@ -2797,13 +2899,13 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.80"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
@ -2812,9 +2914,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.80"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -2822,9 +2924,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.80"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
dependencies = [
"proc-macro2",
"quote",
@ -2835,9 +2937,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.80"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
[[package]]
name = "wayland-client"
@ -2924,9 +3026,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.57"
version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -2934,9 +3036,18 @@ dependencies = [
[[package]]
name = "weezl"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]]
name = "winapi"
@ -3018,7 +3129,7 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
dependencies = [
"nom",
"nom 7.1.1",
]
[[package]]

View file

@ -1,6 +1,6 @@
[package]
name = "mpd_info_screen"
version = "0.2.20"
version = "0.3.0"
edition = "2018"
description = "Displays info on currently playing music from an MPD daemon"
license = "MIT"
@ -12,3 +12,10 @@ repository = "https://github.com/Stephen-Seo/mpd_info_screen"
structopt = "0.3"
image = "0.24"
ggez = "0.7"
freetype = { version = "0.7", optional = true }
[build-dependencies]
bindgen = { version = "0.53", optional = true }
[features]
unicode_support = ["dep:freetype", "dep:bindgen"]

View file

@ -11,9 +11,17 @@ A Rust program that displays info about the currently running MPD server.
The window shows albumart (may be embedded in the audio file, or is a "cover.jpg" in the same directory as the song file), a "time-remaining"
counter, and the filename currently being played
By default, unicode characters will not display properly. Build the project with
the `unicode_support` feature enabled to enable fetching fonts from the local
filesystem to display unicode characters properly (if the system is missing a
font, then it will still be displayed incorrectly).
cargo build --release --features unicode_support
# Usage
mpd_info_screen 0.2.20
mpd_info_screen 0.3.0
USAGE:
mpd_info_screen [FLAGS] [OPTIONS] <host> [port]
@ -42,7 +50,7 @@ Also note that pressing the H key while displaying text will hide the text.
# Issues / TODO
- [ ] UTF-8 Non-ascii font support
- [x] UTF-8 Non-ascii font support (Use the `unicode_support` feature to enable; only tested in linux)
- [x] Support for album art not embedded but in the same directory
## MPD Version
@ -64,3 +72,12 @@ MIT license.
Uses dependency [structopt](https://crates.io/crates/structopt) which is
licensed under Apache-2.0 or MIT licenses.
## Unicode Support Dependencies
Uses dependency
[fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/) which is
[licensed with this license](https://www.freedesktop.org/software/fontconfig/fontconfig-devel/ln12.html).
Uses dependency [freetype](https://freetype.org) which is
[licensed with this license](https://freetype.org/license.html).

25
build.rs Normal file
View file

@ -0,0 +1,25 @@
#[cfg(feature = "unicode_support")]
use bindgen;
use std::env;
use std::path::PathBuf;
#[cfg(not(feature = "unicode_support"))]
fn main() {}
#[cfg(feature = "unicode_support")]
fn main() {
println!("cargo:rustc-link-search=/usr/lib");
println!("cargo:rustc-link-lib=fontconfig");
println!("cargo:rerun-if-changed=src/bindgen_wrapper.h");
let bindings = bindgen::Builder::default()
.header("src/bindgen_wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("unicode_support_bindings.rs"))
.expect("Couldn't write bindings");
}

1
src/bindgen_wrapper.h Normal file
View file

@ -0,0 +1 @@
#include <fontconfig/fontconfig.h>

View file

@ -9,6 +9,7 @@ use ggez::graphics::{
use ggez::{timer, Context, GameError, GameResult};
use image::io::Reader as ImageReader;
use std::io::Cursor;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::{atomic::Ordering, Arc, RwLockReadGuard};
use std::thread;
@ -49,6 +50,125 @@ fn seconds_to_time(seconds: f64) -> String {
result
}
#[cfg(not(feature = "unicode_support"))]
fn string_to_text(
string: String,
loaded_fonts: &mut Vec<(PathBuf, Font)>,
ctx: &mut Context,
) -> Text {
Text::new(TextFragment::from(string))
}
#[cfg(feature = "unicode_support")]
fn string_to_text(
string: String,
loaded_fonts: &mut Vec<(PathBuf, Font)>,
ctx: &mut Context,
) -> Text {
use super::unicode_support;
let mut text = Text::default();
let mut current_fragment = TextFragment::default();
if string.is_ascii() {
current_fragment.text = string;
text.add(current_fragment);
return text;
}
let find_font =
|c: char, loaded_fonts: &mut Vec<(PathBuf, Font)>, ctx: &mut Context| -> Option<usize> {
for (idx, (path, _)) in loaded_fonts.iter().enumerate() {
let result = unicode_support::font_has_char(c, path);
if result.is_ok() && result.unwrap() {
return Some(idx);
}
}
let find_result = unicode_support::get_matching_font_from_char(c);
if let Ok(path) = find_result {
let new_font = Font::new(ctx, &path);
if let Ok(font) = new_font {
loaded_fonts.push((path, font));
return Some(loaded_fonts.len() - 1);
} else {
println!("Failed to load {:?}: {:?}", &path, new_font);
}
} else {
println!("Failed to find font for {}", c);
}
None
};
let mut prev_is_ascii = true;
for c in string.chars() {
if c.is_ascii() {
if prev_is_ascii {
current_fragment.text.push(c);
} else {
if !current_fragment.text.is_empty() {
text.add(current_fragment);
current_fragment = Default::default();
}
current_fragment.text.push(c);
}
prev_is_ascii = true;
} else {
let idx_opt = find_font(c, loaded_fonts, ctx);
if prev_is_ascii {
if let Some(idx) = idx_opt {
if !current_fragment.text.is_empty() {
text.add(current_fragment);
current_fragment = Default::default();
}
let (_, font) = loaded_fonts[idx];
current_fragment.font = Some(font);
}
current_fragment.text.push(c);
} else {
if let Some(idx) = idx_opt {
let font = loaded_fonts[idx].1;
if let Some(current_font) = current_fragment.font {
if current_font == font {
current_fragment.text.push(c);
} else {
if !current_fragment.text.is_empty() {
text.add(current_fragment);
current_fragment = Default::default();
}
current_fragment.text.push(c);
current_fragment.font = Some(font);
}
} else if current_fragment.text.is_empty() {
current_fragment.text.push(c);
current_fragment.font = Some(font);
} else {
text.add(current_fragment);
current_fragment = Default::default();
current_fragment.text.push(c);
current_fragment.font = Some(font);
}
} else {
if !current_fragment.text.is_empty() && current_fragment.font.is_some() {
text.add(current_fragment);
current_fragment = Default::default();
}
current_fragment.text.push(c);
}
}
prev_is_ascii = false;
}
}
if !current_fragment.text.is_empty() {
text.add(current_fragment);
}
text
}
pub struct MPDDisplay {
opts: Opt,
mpd_handler: Result<MPDHandler, String>,
@ -63,10 +183,13 @@ pub struct MPDDisplay {
album_art: Option<Image>,
album_art_draw_transform: Option<Transform>,
filename_text: Text,
filename_string_cache: String,
filename_transform: Transform,
artist_text: Text,
artist_string_cache: String,
artist_transform: Transform,
title_text: Text,
title_string_cache: String,
title_transform: Transform,
timer_text: Text,
timer_transform: Transform,
@ -78,6 +201,7 @@ pub struct MPDDisplay {
hide_text: bool,
tried_album_art_in_dir: bool,
mpd_play_state: MPDPlayState,
loaded_fonts: Vec<(PathBuf, Font)>,
}
impl MPDDisplay {
@ -111,6 +235,10 @@ impl MPDDisplay {
hide_text: false,
tried_album_art_in_dir: false,
mpd_play_state: MPDPlayState::Playing,
loaded_fonts: Vec::new(),
filename_string_cache: String::new(),
artist_string_cache: String::new(),
title_string_cache: String::new(),
}
}
@ -314,13 +442,12 @@ impl MPDDisplay {
break;
}
text.set_font(
Font::default(),
PxScale {
for fragment in text.fragments_mut() {
fragment.scale = Some(PxScale {
x: current_x,
y: current_y,
},
);
});
}
width = text.width(ctx);
height = text.height(ctx);
@ -346,13 +473,12 @@ impl MPDDisplay {
} else {
let diff_scale_y = current_y / height * timer_height;
let current_x = current_x * diff_scale_y / current_y;
text.set_font(
Font::default(),
PxScale {
for fragment in text.fragments_mut() {
fragment.scale = Some(PxScale {
x: current_x,
y: diff_scale_y,
},
);
});
}
*timer_x = current_x;
*timer_y = diff_scale_y;
// width = text.width(ctx); // not really used after this
@ -600,7 +726,14 @@ impl EventHandler for MPDDisplay {
} else {
self.mpd_play_state = MPDPlayState::Playing;
if !shared.title.is_empty() {
self.title_text = Text::new(shared.title.clone());
if shared.title != self.title_string_cache {
self.title_string_cache = shared.title.clone();
self.title_text = string_to_text(
shared.title.clone(),
&mut self.loaded_fonts,
ctx,
);
}
} else {
self.dirty_flag
.as_ref()
@ -608,7 +741,14 @@ impl EventHandler for MPDDisplay {
.store(true, Ordering::Relaxed);
}
if !shared.artist.is_empty() {
self.artist_text = Text::new(shared.artist.clone());
if shared.artist != self.artist_string_cache {
self.artist_string_cache = shared.artist.clone();
self.artist_text = string_to_text(
shared.artist.clone(),
&mut self.loaded_fonts,
ctx,
);
}
} else {
self.dirty_flag
.as_ref()
@ -616,11 +756,18 @@ impl EventHandler for MPDDisplay {
.store(true, Ordering::Relaxed);
}
if !shared.filename.is_empty() {
if self.filename_text.contents() != shared.filename {
self.album_art = None;
self.tried_album_art_in_dir = false;
if shared.filename != self.filename_string_cache {
self.filename_string_cache = shared.filename.clone();
if self.filename_text.contents() != shared.filename {
self.album_art = None;
self.tried_album_art_in_dir = false;
}
self.filename_text = string_to_text(
shared.filename.clone(),
&mut self.loaded_fonts,
ctx,
);
}
self.filename_text = Text::new(shared.filename.clone());
} else {
self.dirty_flag
.as_ref()

View file

@ -1,13 +1,17 @@
mod debug_log;
mod display;
mod mpd_handler;
#[cfg(feature = "unicode_support")]
mod unicode_support;
use ggez::conf::{WindowMode, WindowSetup};
use ggez::event::winit_event::{ElementState, KeyboardInput, ModifiersState};
use ggez::event::{self, ControlFlow, EventHandler};
use ggez::filesystem::mount;
use ggez::graphics::{self, Rect};
use ggez::{ContextBuilder, GameError};
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::thread;
use std::time::{Duration, Instant};
use structopt::StructOpt;
@ -61,6 +65,9 @@ fn main() -> Result<(), String> {
.build()
.expect("Failed to create ggez context");
// mount "/" read-only so that fonts can be loaded via absolute paths
mount(&mut ctx, &PathBuf::from("/"), true);
let mut display = display::MPDDisplay::new(&mut ctx, opt.clone());
let mut modifiers_state: ModifiersState = ModifiersState::default();

5
src/unicode_support.rs Normal file
View file

@ -0,0 +1,5 @@
mod fontconfig;
mod freetype;
pub use self::freetype::font_has_char;
pub use fontconfig::{get_matching_font_from_char, get_matching_font_from_str};

View file

@ -0,0 +1,348 @@
use std::{path::PathBuf, str::FromStr};
mod ffi {
use std::{ffi::CStr, os::raw::c_int};
mod bindgen {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(deref_nullptr)]
include!(concat!(env!("OUT_DIR"), "/unicode_support_bindings.rs"));
}
pub struct FcConfigWr {
config: *mut bindgen::FcConfig,
}
impl Drop for FcConfigWr {
fn drop(&mut self) {
if !self.config.is_null() {
unsafe {
bindgen::FcConfigDestroy(self.config);
}
}
}
}
impl FcConfigWr {
pub fn new() -> Result<Self, String> {
let config = unsafe { bindgen::FcInitLoadConfigAndFonts() };
if config.is_null() {
Err(String::from("Failed to create FcConfig"))
} else {
Ok(Self { config })
}
}
pub fn get(&mut self) -> *mut bindgen::FcConfig {
self.config
}
pub fn apply_pattern_to_config(&mut self, pattern: &mut FcPatternWr) -> bool {
unsafe {
bindgen::FcConfigSubstitute(
self.config,
pattern.get(),
bindgen::_FcMatchKind_FcMatchPattern,
) == bindgen::FcTrue as bindgen::FcBool
}
}
pub fn font_match(&mut self, pattern: &mut FcPatternWr) -> Result<FcPatternWr, String> {
unsafe {
let mut result: bindgen::FcResult = 0 as bindgen::FcResult;
let result_pattern = bindgen::FcFontMatch(
self.config,
pattern.get(),
&mut result as *mut bindgen::FcResult,
);
if result != bindgen::_FcResult_FcResultMatch {
if !result_pattern.is_null() {
bindgen::FcPatternDestroy(result_pattern);
return Err(String::from("Failed to FcFontMatch (FcResult is not FcResultMatch; result_pattern is not null)"));
} else {
return Err(format!(
"Failed to FcFontMatch (FcResult is not FcResultMatch; {:?})",
result
));
}
} else if result_pattern.is_null() {
return Err(String::from(
"Failed to FcFontMatch (result_pattern is null)",
));
}
Ok(FcPatternWr {
pattern: result_pattern,
})
}
}
}
pub struct FcCharSetWr {
charset: *mut bindgen::FcCharSet,
}
impl Drop for FcCharSetWr {
fn drop(&mut self) {
if !self.charset.is_null() {
unsafe {
bindgen::FcCharSetDestroy(self.charset);
}
}
}
}
impl FcCharSetWr {
pub fn new_with_str(s: &str) -> Result<Self, String> {
let charset;
unsafe {
let charset_ptr = bindgen::FcCharSetCreate();
if charset_ptr.is_null() {
return Err(String::from("Failed to create FcCharSet with str"));
}
charset = FcCharSetWr {
charset: charset_ptr,
};
for c in s.chars() {
if bindgen::FcCharSetAddChar(charset.charset, c as u32)
== bindgen::FcFalse as bindgen::FcBool
{
return Err(String::from("Failed to add chars from str into FcCharSet"));
}
}
}
Ok(charset)
}
pub fn new_with_char(c: char) -> Result<Self, String> {
let charset;
unsafe {
let charset_ptr = bindgen::FcCharSetCreate();
if charset_ptr.is_null() {
return Err(String::from("Failed to create FcCharSet with char"));
}
charset = FcCharSetWr {
charset: charset_ptr,
};
if bindgen::FcCharSetAddChar(charset.charset, c as u32)
== bindgen::FcFalse as bindgen::FcBool
{
return Err(String::from("Failed to add char to FcCharSet"));
}
}
Ok(charset)
}
pub fn get(&mut self) -> *mut bindgen::FcCharSet {
self.charset
}
}
pub struct FcPatternWr {
pattern: *mut bindgen::FcPattern,
}
impl Drop for FcPatternWr {
fn drop(&mut self) {
if !self.pattern.is_null() {
unsafe {
bindgen::FcPatternDestroy(self.pattern);
}
}
}
}
impl FcPatternWr {
pub fn new_with_charset(c: &mut FcCharSetWr) -> Result<Self, String> {
let pattern;
unsafe {
let pattern_ptr = bindgen::FcPatternCreate();
if pattern_ptr.is_null() {
return Err(String::from("Failed to FcPatternCreate"));
}
pattern = Self {
pattern: pattern_ptr,
};
bindgen::FcDefaultSubstitute(pattern.pattern);
let value = bindgen::FcValue {
type_: bindgen::_FcType_FcTypeCharSet,
u: bindgen::_FcValue__bindgen_ty_1 { c: c.get() },
};
if bindgen::FcPatternAdd(
pattern.pattern,
bindgen::FC_CHARSET as *const _ as *const i8,
value,
bindgen::FcTrue as bindgen::FcBool,
) == bindgen::FcFalse as bindgen::FcBool
{
return Err(String::from("Failed to add FcCharSet to new Pattern"));
}
}
Ok(pattern)
}
pub fn get(&mut self) -> *mut bindgen::FcPattern {
self.pattern
}
pub fn get_count(&self) -> c_int {
unsafe { bindgen::FcPatternObjectCount(self.pattern) }
}
pub fn filter_to_filenames(&self) -> Result<Self, String> {
let pattern;
unsafe {
let mut file_object_set_filter = FcObjectSetWr::new_file_object_set()?;
let pattern_ptr =
bindgen::FcPatternFilter(self.pattern, file_object_set_filter.get());
if pattern_ptr.is_null() {
return Err(String::from("Failed to FcPatternFilter"));
}
pattern = Self {
pattern: pattern_ptr,
};
}
Ok(pattern)
}
pub fn get_filename_contents(&self) -> Result<Vec<String>, String> {
let mut vec: Vec<String> = Vec::new();
let count = self.get_count();
unsafe {
let mut value = bindgen::FcValue {
type_: 0,
u: bindgen::_FcValue__bindgen_ty_1 { i: 0 },
};
for i in 0..count {
if bindgen::FcPatternGet(
self.pattern,
bindgen::FC_FILE as *const _ as *const i8,
i,
&mut value as *mut bindgen::FcValue,
) == bindgen::_FcResult_FcResultMatch
{
if value.type_ == bindgen::_FcType_FcTypeString {
let cs = CStr::from_ptr(value.u.s as *const i8);
vec.push(
cs.to_str()
.map_err(|_| String::from("Failed to convert CStr to String"))?
.to_owned(),
);
}
}
}
}
Ok(vec)
}
}
struct FcObjectSetWr {
object_set: *mut bindgen::FcObjectSet,
}
impl Drop for FcObjectSetWr {
fn drop(&mut self) {
unsafe {
if !self.object_set.is_null() {
bindgen::FcObjectSetDestroy(self.object_set);
}
}
}
}
impl FcObjectSetWr {
pub fn new_file_object_set() -> Result<Self, String> {
let object_set;
unsafe {
let object_set_ptr = bindgen::FcObjectSetCreate();
if object_set_ptr.is_null() {
return Err(String::from("Failed to FcObjectSetCreate"));
}
object_set = Self {
object_set: object_set_ptr,
};
if bindgen::FcObjectSetAdd(
object_set.object_set,
bindgen::FC_FILE as *const _ as *const i8,
) == bindgen::FcFalse as bindgen::FcBool
{
return Err(String::from(
"Failed to add \"FC_FILE\" with FcObjectSetAdd",
));
}
}
Ok(object_set)
}
pub fn get(&mut self) -> *mut bindgen::FcObjectSet {
self.object_set
}
}
}
pub fn get_matching_font_from_str(s: &str) -> Result<PathBuf, String> {
let mut config = ffi::FcConfigWr::new()?;
let mut charset = ffi::FcCharSetWr::new_with_str(s)?;
let mut search_pattern = ffi::FcPatternWr::new_with_charset(&mut charset)?;
if !config.apply_pattern_to_config(&mut search_pattern) {
return Err(String::from("Failed to apply_pattern_to_config"));
}
let result_pattern = config.font_match(&mut search_pattern)?;
let filtered_pattern = result_pattern.filter_to_filenames()?;
let result_vec = filtered_pattern.get_filename_contents()?;
if result_vec.is_empty() {
Err(String::from(
"Empty result_vec for get_matching_font_from_str",
))
} else {
PathBuf::from_str(&result_vec[0]).map_err(|e| e.to_string())
}
}
pub fn get_matching_font_from_char(c: char) -> Result<PathBuf, String> {
let mut config = ffi::FcConfigWr::new()?;
let mut charset = ffi::FcCharSetWr::new_with_char(c)?;
let mut search_pattern = ffi::FcPatternWr::new_with_charset(&mut charset)?;
if !config.apply_pattern_to_config(&mut search_pattern) {
return Err(String::from("Failed to apply_pattern_to_config"));
}
let result_pattern = config.font_match(&mut search_pattern)?;
let filtered_pattern = result_pattern.filter_to_filenames()?;
let result_vec = filtered_pattern.get_filename_contents()?;
if result_vec.is_empty() {
Err(String::from(
"Empty result_vec for get_matching_font_from_char",
))
} else {
PathBuf::from_str(&result_vec[0]).map_err(|e| e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ascii_fetching() {
let fetched_path =
get_matching_font_from_char('a').expect("Should be able to find match for 'a'");
println!("{:?}", fetched_path);
}
}

View file

@ -0,0 +1,157 @@
use std::path::Path;
mod ffi {
use freetype::freetype::{
FT_Done_Face, FT_Done_Library, FT_Face, FT_FaceRec_, FT_Get_Char_Index, FT_Init_FreeType,
FT_Library, FT_ModuleRec_, FT_Open_Args, FT_Open_Face, FT_Parameter_, FT_StreamRec_,
FT_OPEN_PATHNAME,
};
use std::ffi::CString;
use std::path::Path;
pub struct FTLibrary {
library: FT_Library,
}
impl Drop for FTLibrary {
fn drop(&mut self) {
if !self.library.is_null() {
unsafe {
FT_Done_Library(self.library);
}
}
}
}
impl FTLibrary {
pub fn new() -> Option<FTLibrary> {
unsafe {
let mut library_ptr: FT_Library = 0 as FT_Library;
if FT_Init_FreeType(&mut library_ptr) != 0 {
Some(FTLibrary {
library: library_ptr,
})
} else {
None
}
}
}
pub fn get(&self) -> FT_Library {
self.library
}
}
pub struct FTOpenArgs {
args: FT_Open_Args,
pathname: Option<CString>,
}
impl FTOpenArgs {
pub fn new_with_path(path: &Path) -> Self {
unsafe {
let cstring: CString = CString::from_vec_unchecked(
path.as_os_str().to_str().unwrap().as_bytes().to_vec(),
);
let args = FT_Open_Args {
flags: FT_OPEN_PATHNAME,
memory_base: 0 as *const u8,
memory_size: 0,
pathname: cstring.as_ptr() as *mut i8,
stream: 0 as *mut FT_StreamRec_,
driver: 0 as *mut FT_ModuleRec_,
num_params: 0,
params: 0 as *mut FT_Parameter_,
};
FTOpenArgs {
args,
pathname: Some(cstring),
}
}
}
pub fn get_args(&self) -> FT_Open_Args {
self.args
}
pub fn get_ptr(&mut self) -> *mut FT_Open_Args {
&mut self.args as *mut FT_Open_Args
}
}
pub struct FTFaces {
faces: Vec<FT_Face>,
}
impl Drop for FTFaces {
fn drop(&mut self) {
for face in &self.faces {
unsafe {
FT_Done_Face(*face);
}
}
}
}
impl FTFaces {
pub fn new(library: &FTLibrary, args: &mut FTOpenArgs) -> Result<FTFaces, ()> {
let mut faces = FTFaces { faces: Vec::new() };
unsafe {
let count;
let mut face: FT_Face = 0 as FT_Face;
// first get number of faces
let mut result = FT_Open_Face(
library.get(),
args.get_ptr(),
-1,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(());
}
count = (*face).num_faces;
for i in 0..count {
result = FT_Open_Face(
library.get(),
args.get_ptr(),
i,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(());
}
faces.faces.push(face);
}
}
Ok(faces)
}
pub fn has_char(&self, c: char) -> bool {
let char_value: u64 = c as u64;
for face in &self.faces {
unsafe {
let result = FT_Get_Char_Index(*face, char_value);
if result != 0 {
return true;
}
}
}
false
}
}
}
pub fn font_has_char(c: char, font_path: &Path) -> Result<bool, ()> {
let library = ffi::FTLibrary::new().ok_or(())?;
let mut args = ffi::FTOpenArgs::new_with_path(font_path);
let faces = ffi::FTFaces::new(&library, &mut args)?;
Ok(faces.has_char(c))
}