Remove `pathfinder_font_renderer` in favor of `font-kit`.
Closes #69. Closes #84.
This commit is contained in:
parent
a518cdac21
commit
c6cc6e6fd8
|
@ -67,6 +67,27 @@ dependencies = [
|
|||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.6.0"
|
||||
|
@ -109,6 +130,11 @@ name = "bitflags"
|
|||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.3"
|
||||
|
@ -174,6 +200,18 @@ dependencies = [
|
|||
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.0.1"
|
||||
|
@ -193,35 +231,35 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation-sys 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "11.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "13.0.0"
|
||||
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||
dependencies = [
|
||||
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -266,18 +304,30 @@ dependencies = [
|
|||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dwrite-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "dwrote"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/servo/dwrote-rs#28896a9346e60fdd7e3b929494bd7f7bfe0c2e72"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -306,6 +356,69 @@ dependencies = [
|
|||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "expat-sys"
|
||||
version = "2.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-ord"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "font-kit"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pcwalton/font-kit#b6c001f663839961b70fcea1101398f589ce4fb9"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cocoa 0.18.0 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"core-text 13.0.0 (git+https://github.com/servo/core-foundation-rs)",
|
||||
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.5.0 (git+https://github.com/servo/dwrote-rs)",
|
||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.1 (git+https://github.com/servo/rust-freetype)",
|
||||
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontsan"
|
||||
version = "0.4.0"
|
||||
|
@ -331,8 +444,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "freetype"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/servo/rust-freetype#e6ead0a811a604654d410c8ce9c43ee142329adc"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -528,6 +641,14 @@ dependencies = [
|
|||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.2"
|
||||
|
@ -542,15 +663,6 @@ dependencies = [
|
|||
"rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
|
@ -623,6 +735,14 @@ name = "lzw"
|
|||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.6"
|
||||
|
@ -636,6 +756,15 @@ dependencies = [
|
|||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.2.1"
|
||||
|
@ -713,6 +842,14 @@ dependencies = [
|
|||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.5.0"
|
||||
|
@ -729,36 +866,13 @@ dependencies = [
|
|||
name = "pathfinder"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)",
|
||||
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_font_renderer 0.5.0",
|
||||
"pathfinder_partitioner 0.2.0",
|
||||
"pathfinder_path_utils 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_font_renderer"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-text 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_gfx_utils"
|
||||
version = "0.2.0"
|
||||
|
@ -805,6 +919,7 @@ dependencies = [
|
|||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)",
|
||||
"fontsan 0.4.0 (git+https://github.com/servo/fontsan.git)",
|
||||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -812,7 +927,6 @@ dependencies = [
|
|||
"lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_font_renderer 0.5.0",
|
||||
"pathfinder_partitioner 0.2.0",
|
||||
"pathfinder_path_utils 0.2.0",
|
||||
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/rocket)",
|
||||
|
@ -1050,11 +1164,24 @@ dependencies = [
|
|||
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.9"
|
||||
|
@ -1093,6 +1220,25 @@ dependencies = [
|
|||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig-sys"
|
||||
version = "4.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-freetype-sys"
|
||||
version = "4.0.3"
|
||||
|
@ -1130,6 +1276,17 @@ dependencies = [
|
|||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "0.3.6"
|
||||
|
@ -1257,15 +1414,6 @@ name = "utf8-ranges"
|
|||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "uuid-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
|
@ -1281,6 +1429,15 @@ name = "void"
|
|||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
|
@ -1295,11 +1452,6 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -1336,12 +1488,15 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum atk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33a67fd81e1922dddc335887516f2f5254534e89c9d39fa89bca5d79bd150d34"
|
||||
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e"
|
||||
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
|
||||
"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9"
|
||||
"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
|
||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
|
||||
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
|
||||
"checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13"
|
||||
"checksum cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b5695f59fd036fe5741bc5a4eb20c78fbe42256e3b08a2af26bbcbe8070bf3"
|
||||
|
@ -1350,25 +1505,32 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3"
|
||||
"checksum cocoa 0.18.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
|
||||
"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>"
|
||||
"checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2"
|
||||
"checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9"
|
||||
"checksum core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92801c908ea6301ae619ed842a72e01098085fc321b9c2f3f833dad555bba055"
|
||||
"checksum core-text 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "157ff38a92496dc676ce36d9124554e9ac66f1c1039f952690ac64f71cfa5968"
|
||||
"checksum core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||
"checksum core-foundation-sys 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||
"checksum core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||
"checksum core-text 13.0.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||
"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"
|
||||
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
|
||||
"checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444"
|
||||
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
|
||||
"checksum dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7918280f33862bc8542212d74f2149b1a87ab402fd15f4ce9a1c56582958d6e"
|
||||
"checksum dwrote 0.5.0 (git+https://github.com/servo/dwrote-rs)" = "<none>"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
|
||||
"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"
|
||||
"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
|
||||
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
|
||||
"checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
|
||||
"checksum font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)" = "<none>"
|
||||
"checksum fontsan 0.4.0 (git+https://github.com/servo/fontsan.git)" = "<none>"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
"checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
|
||||
"checksum freetype 0.4.1 (git+https://github.com/servo/rust-freetype)" = "<none>"
|
||||
"checksum gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16160d212ae91abe9f3324c3fb233929ba322dde63585d15cda3336f8c529ed1"
|
||||
"checksum gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "798f97101eea8180da363d0e80e07ec7ec6d1809306601c0100c1de5bc8b4f52"
|
||||
"checksum gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ee916f5f25c5f4b21bd9dcb12a216ae697406940ff9476358c308a8ececada"
|
||||
|
@ -1386,9 +1548,9 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
|
||||
"checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245"
|
||||
"checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522"
|
||||
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
|
||||
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
|
||||
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3"
|
||||
|
@ -1400,8 +1562,10 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "216bfb2b880554865fa9deaa14671ab9f1368b942e7007cc8c97c083ac8a7f45"
|
||||
"checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843"
|
||||
"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.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
|
||||
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
|
||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||
|
@ -1412,6 +1576,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
|
||||
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9833ab0efe5361b1e2122a0544a5d3359576911a42cb098c2e59be8650807367"
|
||||
"checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab"
|
||||
"checksum pear 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=b475140)" = "<none>"
|
||||
"checksum pear_codegen 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=b475140)" = "<none>"
|
||||
|
@ -1435,17 +1600,22 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/rocket)" = "<none>"
|
||||
"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"
|
||||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
||||
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
|
||||
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920"
|
||||
"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124"
|
||||
"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2"
|
||||
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
|
||||
"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a"
|
||||
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
|
||||
"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8"
|
||||
"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 syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
|
||||
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
|
||||
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
|
@ -1464,13 +1634,12 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
|
|||
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
|
||||
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum uuid-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "383cea1fd3b68c33bbdd25af09bc50e70f4c9f1d9b18e39e514e4acf760ec5d2"
|
||||
"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"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"font-renderer",
|
||||
"gfx-utils",
|
||||
"partitioner",
|
||||
"path-utils",
|
||||
|
|
|
@ -5,8 +5,8 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
|||
|
||||
[features]
|
||||
default = []
|
||||
freetype = ["pathfinder_font_renderer/freetype"]
|
||||
reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"]
|
||||
freetype = ["font-kit/loader-freetype-default"]
|
||||
reftests = ["rsvg", "cairo-rs", "font-kit/loader-freetype-default"]
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
|
@ -45,8 +45,8 @@ git = "https://github.com/SergioBenitez/rocket"
|
|||
[dependencies.rocket_contrib]
|
||||
git = "https://github.com/SergioBenitez/rocket"
|
||||
|
||||
[dependencies.pathfinder_font_renderer]
|
||||
path = "../../font-renderer"
|
||||
[dependencies.font-kit]
|
||||
git = "https://github.com/pcwalton/font-kit"
|
||||
|
||||
[dependencies.pathfinder_partitioner]
|
||||
path = "../../partitioner"
|
||||
|
|
|
@ -15,12 +15,12 @@ extern crate app_units;
|
|||
extern crate base64;
|
||||
extern crate env_logger;
|
||||
extern crate euclid;
|
||||
extern crate font_kit;
|
||||
extern crate fontsan;
|
||||
extern crate image;
|
||||
extern crate lru_cache;
|
||||
extern crate lyon_geom;
|
||||
extern crate lyon_path;
|
||||
extern crate pathfinder_font_renderer;
|
||||
extern crate pathfinder_partitioner;
|
||||
extern crate pathfinder_path_utils;
|
||||
extern crate rocket;
|
||||
|
@ -36,15 +36,17 @@ extern crate cairo;
|
|||
#[cfg(feature = "reftests")]
|
||||
extern crate rsvg;
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::{Point2D, Transform2D};
|
||||
use font_kit::canvas::Format as FontKitFormat;
|
||||
use font_kit::canvas::{Canvas, RasterizationOptions};
|
||||
use font_kit::font::Font;
|
||||
use font_kit::hinting::HintingOptions;
|
||||
use font_kit::loaders;
|
||||
use image::{DynamicImage, ImageBuffer, ImageFormat, ImageRgba8};
|
||||
use lru_cache::LruCache;
|
||||
use lyon_path::PathEvent;
|
||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
||||
use lyon_path::iterator::PathIter;
|
||||
use pathfinder_font_renderer::{FontContext, FontInstance, GlyphImage};
|
||||
use pathfinder_font_renderer::{GlyphKey, SubpixelOffset};
|
||||
use pathfinder_partitioner::FillRule;
|
||||
use pathfinder_partitioner::mesh_pack::MeshPack;
|
||||
use pathfinder_partitioner::partitioner::Partitioner;
|
||||
|
@ -58,14 +60,10 @@ use rocket_contrib::json::Json;
|
|||
use std::fs::File;
|
||||
use std::io::{self, Cursor, Read};
|
||||
use std::path::{self, PathBuf};
|
||||
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::u32;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use pathfinder_font_renderer::core_graphics;
|
||||
|
||||
#[cfg(feature = "reftests")]
|
||||
use euclid::Size2D;
|
||||
#[cfg(feature = "reftests")]
|
||||
|
@ -79,8 +77,6 @@ const MESH_PACK_CACHE_SIZE: usize = 16;
|
|||
|
||||
const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 5.0;
|
||||
|
||||
static NEXT_FONT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
lazy_static! {
|
||||
static ref MESH_PACK_CACHE: Mutex<LruCache<MeshPackCacheKey, PartitionResponder>> = {
|
||||
Mutex::new(LruCache::new(MESH_PACK_CACHE_SIZE))
|
||||
|
@ -267,15 +263,6 @@ struct PartitionSvgPathCommand {
|
|||
values: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
struct FontKey(usize);
|
||||
|
||||
impl FontKey {
|
||||
fn new() -> FontKey {
|
||||
FontKey(NEXT_FONT_KEY.fetch_add(1, Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
struct PathPartitioningResult {
|
||||
encoded_data: Arc<Vec<u8>>,
|
||||
time: Duration,
|
||||
|
@ -409,31 +396,6 @@ fn svg_data_from_request(builtin_svg_name: &str) -> Result<Arc<Vec<u8>>, SvgErro
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn rasterize_glyph_with_core_graphics(font_key: &FontKey,
|
||||
font_index: u32,
|
||||
otf_data: Arc<Vec<u8>>,
|
||||
font_instance: &FontInstance<FontKey>,
|
||||
glyph_key: &GlyphKey)
|
||||
-> Result<GlyphImage, FontError> {
|
||||
let mut font_context =
|
||||
try!(core_graphics::FontContext::new().map_err(|_| FontError::FontLoadingFailed));
|
||||
try!(font_context.add_font_from_memory(font_key, otf_data, font_index)
|
||||
.map_err(|_| FontError::FontLoadingFailed));
|
||||
font_context.rasterize_glyph_with_native_rasterizer(&font_instance, &glyph_key, true)
|
||||
.map_err(|_| FontError::RasterizationFailed)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn rasterize_glyph_with_core_graphics(_: &FontKey,
|
||||
_: u32,
|
||||
_: Arc<Vec<u8>>,
|
||||
_: &FontInstance<FontKey>,
|
||||
_: &GlyphKey)
|
||||
-> Result<GlyphImage, FontError> {
|
||||
Err(FontError::ReferenceRasterizerUnavailable)
|
||||
}
|
||||
|
||||
#[post("/partition-font", format = "application/json", data = "<request>")]
|
||||
fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionResponder, FontError> {
|
||||
// Check the cache.
|
||||
|
@ -456,23 +418,10 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
|
|||
}
|
||||
|
||||
// Parse glyph data.
|
||||
let mut font_context = match FontContext::new() {
|
||||
Ok(font_context) => font_context,
|
||||
Err(_) => {
|
||||
println!("Failed to create a font context!");
|
||||
return Err(FontError::FontLoadingFailed)
|
||||
}
|
||||
};
|
||||
|
||||
let font_key = FontKey::new();
|
||||
let otf_data = try!(otf_data_from_request(&request.face));
|
||||
if font_context.add_font_from_memory(&font_key, otf_data, request.font_index).is_err() {
|
||||
return Err(FontError::FontLoadingFailed)
|
||||
}
|
||||
|
||||
let font_instance = FontInstance {
|
||||
font_key: font_key,
|
||||
size: Au::from_f64_px(request.point_size),
|
||||
let font = match Font::from_bytes(otf_data, request.font_index) {
|
||||
Ok(font) => font,
|
||||
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||
};
|
||||
|
||||
// Read glyph info.
|
||||
|
@ -480,12 +429,12 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
|
|||
let mut path_descriptors = vec![];
|
||||
|
||||
for (glyph_index, glyph) in request.glyphs.iter().enumerate() {
|
||||
let glyph_key = GlyphKey::new(glyph.id, SubpixelOffset(0));
|
||||
|
||||
// This might fail; if so, just leave it blank.
|
||||
match font_context.glyph_outline(&font_instance, &glyph_key) {
|
||||
Ok(glyph_outline) => {
|
||||
paths.push(Transform2DPathIter::new(glyph_outline.iter(),
|
||||
// FIXME(pcwalton): Should we add first-class support for transforms to `font-kit`?
|
||||
let mut path_builder = lyon_path::default::Path::builder();
|
||||
match font.outline(glyph.id, HintingOptions::None, &mut path_builder) {
|
||||
Ok(()) => {
|
||||
paths.push(Transform2DPathIter::new(path_builder.build().into_iter(),
|
||||
&glyph.transform).collect())
|
||||
}
|
||||
Err(_) => paths.push(vec![]),
|
||||
|
@ -601,39 +550,60 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|||
#[post("/render-reference/text", format = "application/json", data = "<request>")]
|
||||
fn render_reference_text(request: Json<RenderTextReferenceRequest>)
|
||||
-> Result<ReferenceImage, FontError> {
|
||||
let font_key = FontKey::new();
|
||||
let otf_data = try!(otf_data_from_request(&request.face));
|
||||
let font_instance = FontInstance {
|
||||
font_key: font_key,
|
||||
size: Au::from_f64_px(request.point_size),
|
||||
};
|
||||
let glyph_key = GlyphKey::new(request.glyph, SubpixelOffset(0));
|
||||
|
||||
// Rasterize the glyph using the right rasterizer.
|
||||
let glyph_image = match request.renderer {
|
||||
let mut canvas;
|
||||
match request.renderer {
|
||||
ReferenceTextRenderer::FreeType => {
|
||||
let mut font_context =
|
||||
try!(FontContext::new().map_err(|_| FontError::FontLoadingFailed));
|
||||
try!(font_context.add_font_from_memory(&font_key, otf_data, request.font_index)
|
||||
.map_err(|_| FontError::FontLoadingFailed));
|
||||
try!(font_context.rasterize_glyph_with_native_rasterizer(&font_instance,
|
||||
&glyph_key,
|
||||
true)
|
||||
.map_err(|_| FontError::RasterizationFailed))
|
||||
let loader = match Font::from_bytes(otf_data, request.font_index) {
|
||||
Ok(loader) => loader,
|
||||
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||
};
|
||||
let glyph_rect = try!(loader.raster_bounds(request.glyph,
|
||||
request.point_size as f32,
|
||||
&Point2D::zero(),
|
||||
HintingOptions::None,
|
||||
RasterizationOptions::SubpixelAa)
|
||||
.map_err(|_| FontError::RasterizationFailed));
|
||||
let glyph_dimensions = glyph_rect.size.to_u32();
|
||||
canvas = Canvas::new(&glyph_dimensions, FontKitFormat::Rgba32);
|
||||
let origin = Point2D::new(-glyph_rect.origin.x, -glyph_rect.origin.y).to_f32();
|
||||
try!(loader.rasterize_glyph(&mut canvas,
|
||||
request.glyph,
|
||||
request.point_size as f32,
|
||||
&origin,
|
||||
HintingOptions::None,
|
||||
RasterizationOptions::SubpixelAa)
|
||||
.map_err(|_| FontError::RasterizationFailed));
|
||||
}
|
||||
ReferenceTextRenderer::CoreGraphics => {
|
||||
try!(rasterize_glyph_with_core_graphics(&font_key,
|
||||
request.font_index,
|
||||
otf_data,
|
||||
&font_instance,
|
||||
&glyph_key))
|
||||
let loader = match loaders::core_text::Font::from_bytes(otf_data, request.font_index) {
|
||||
Ok(loader) => loader,
|
||||
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||
};
|
||||
let glyph_rect = try!(loader.raster_bounds(request.glyph,
|
||||
request.point_size as f32,
|
||||
&Point2D::zero(),
|
||||
HintingOptions::None,
|
||||
RasterizationOptions::SubpixelAa)
|
||||
.map_err(|_| FontError::RasterizationFailed));
|
||||
let glyph_dimensions = glyph_rect.size.to_u32();
|
||||
canvas = Canvas::new(&glyph_dimensions, FontKitFormat::Rgba32);
|
||||
let origin = Point2D::new(-glyph_rect.origin.x, -glyph_rect.origin.y).to_f32();
|
||||
try!(loader.rasterize_glyph(&mut canvas,
|
||||
request.glyph,
|
||||
request.point_size as f32,
|
||||
&origin,
|
||||
HintingOptions::None,
|
||||
RasterizationOptions::SubpixelAa)
|
||||
.map_err(|_| FontError::RasterizationFailed));
|
||||
}
|
||||
};
|
||||
|
||||
let dimensions = &glyph_image.dimensions;
|
||||
let image_buffer = ImageBuffer::from_raw(dimensions.size.width,
|
||||
dimensions.size.height,
|
||||
glyph_image.pixels).unwrap();
|
||||
let image_buffer = ImageBuffer::from_raw(canvas.size.width,
|
||||
canvas.size.height,
|
||||
canvas.pixels).unwrap();
|
||||
let reference_image = ReferenceImage {
|
||||
image: ImageRgba8(image_buffer),
|
||||
};
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
[package]
|
||||
name = "pathfinder_font_renderer"
|
||||
version = "0.5.0"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
freetype-backend = ["freetype"]
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
libc = "0.2"
|
||||
log = "0.3"
|
||||
lyon_path = "0.12"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
||||
[dependencies.euclid]
|
||||
version = "0.19"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.freetype]
|
||||
version = "0.4"
|
||||
optional = true
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "ios")))'.dependencies]
|
||||
freetype = { version = "0.4" }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-graphics = "0.16"
|
||||
core-text = "11"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
dwrite-sys = "0.2"
|
||||
kernel32-sys = "0.2"
|
||||
uuid-sys = "0.1"
|
||||
winapi = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.5"
|
|
@ -1,346 +0,0 @@
|
|||
// pathfinder/font-renderer/src/core_graphics.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Font loading using macOS Core Graphics/Quartz.
|
||||
|
||||
use core_graphics_sys::base::{CGFloat, kCGImageAlphaNoneSkipFirst, kCGBitmapByteOrder32Little};
|
||||
use core_graphics_sys::color_space::CGColorSpace;
|
||||
use core_graphics_sys::context::{CGContext, CGTextDrawingMode};
|
||||
use core_graphics_sys::data_provider::CGDataProvider;
|
||||
use core_graphics_sys::font::{CGFont, CGGlyph};
|
||||
use core_graphics_sys::geometry::{CG_AFFINE_TRANSFORM_IDENTITY, CGPoint, CGRect};
|
||||
use core_graphics_sys::geometry::{CGSize, CG_ZERO_POINT};
|
||||
use core_graphics_sys::path::CGPathElementType;
|
||||
use core_text::font::CTFont;
|
||||
use core_text;
|
||||
use euclid::{Point2D, Rect, Size2D, Vector2D};
|
||||
use lyon_path::PathEvent;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Cloned;
|
||||
use std::slice::Iter;
|
||||
use std::sync::Arc;
|
||||
use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey};
|
||||
|
||||
const CG_ZERO_RECT: CGRect = CGRect {
|
||||
origin: CG_ZERO_POINT,
|
||||
size: CGSize {
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
},
|
||||
};
|
||||
|
||||
// A conservative overestimate of the amount of font dilation that Core Graphics performs, as a
|
||||
// fraction of ppem.
|
||||
//
|
||||
// The actual amount as of High Sierra is 0.0121 in the X direction and 0.015125 in the Y
|
||||
// direction.
|
||||
const FONT_DILATION_AMOUNT: f32 = 0.02;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[derive(Clone)]
|
||||
pub struct NativeFontHandle(pub CGFont);
|
||||
|
||||
/// An object that loads and renders fonts using macOS Core Graphics/Quartz.
|
||||
pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
core_graphics_fonts: BTreeMap<FK, CGFont>,
|
||||
core_text_fonts: BTreeMap<FontInstance<FK>, CTFont>,
|
||||
}
|
||||
|
||||
// Core Text is thread-safe.
|
||||
unsafe impl<FK> Send for FontContext<FK> where FK: Clone + Hash + Eq + Ord + Send {}
|
||||
|
||||
impl<FK> FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
/// Creates a new font context instance.
|
||||
pub fn new() -> Result<Self, ()> {
|
||||
Ok(FontContext {
|
||||
core_graphics_fonts: BTreeMap::new(),
|
||||
core_text_fonts: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Loads an OpenType font from a Quartz `CGFont` handle.
|
||||
pub fn add_native_font<H>(&mut self, font_key: &FK, handle: H) -> Result<(), ()>
|
||||
where H: Into<CGFont> {
|
||||
match self.core_graphics_fonts.entry((*font_key).clone()) {
|
||||
Entry::Occupied(_) => Ok(()),
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(handle.into());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads an OpenType font from memory.
|
||||
///
|
||||
/// `font_key` is a handle that is used to refer to the font later. If this context has already
|
||||
/// loaded a font with the same font key, nothing is done, and `Ok` is returned.
|
||||
///
|
||||
/// `bytes` is the raw OpenType data (i.e. the contents of the `.otf` or `.ttf` file on disk).
|
||||
///
|
||||
/// `font_index` is the index of the font within the collection, if `bytes` refers to a
|
||||
/// collection (`.ttc`).
|
||||
pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, _: u32)
|
||||
-> Result<(), ()> {
|
||||
match self.core_graphics_fonts.entry((*font_key).clone()) {
|
||||
Entry::Occupied(_) => Ok(()),
|
||||
Entry::Vacant(entry) => {
|
||||
let data_provider = CGDataProvider::from_buffer(bytes);
|
||||
let core_graphics_font = try!(CGFont::from_data_provider(data_provider));
|
||||
entry.insert(core_graphics_font);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unloads the font with the given font key from memory.
|
||||
///
|
||||
/// If the font isn't loaded, does nothing.
|
||||
pub fn delete_font(&mut self, font_key: &FK) {
|
||||
self.core_graphics_fonts.remove(font_key);
|
||||
|
||||
let core_text_font_keys: Vec<_> = self.core_text_fonts
|
||||
.keys()
|
||||
.filter(|key| key.font_key == *font_key)
|
||||
.cloned()
|
||||
.collect();
|
||||
for core_text_font_key in &core_text_font_keys {
|
||||
self.core_text_fonts.remove(core_text_font_key);
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_core_text_font(&mut self, font_instance: &FontInstance<FK>) -> Result<CTFont, ()> {
|
||||
match self.core_text_fonts.entry((*font_instance).clone()) {
|
||||
Entry::Occupied(entry) => Ok((*entry.get()).clone()),
|
||||
Entry::Vacant(entry) => {
|
||||
let core_graphics_font = match self.core_graphics_fonts
|
||||
.get(&font_instance.font_key) {
|
||||
None => return Err(()),
|
||||
Some(core_graphics_font) => core_graphics_font,
|
||||
};
|
||||
|
||||
let core_text_font = try!(font_instance.instantiate(&core_graphics_font));
|
||||
entry.insert(core_text_font.clone());
|
||||
Ok(core_text_font)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the dimensions of the given glyph in the given font.
|
||||
///
|
||||
/// If `exact` is true, then the raw outline extents as specified by the font designer are
|
||||
/// returned. These may differ from the extents when rendered on screen, because some font
|
||||
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
||||
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
||||
/// set `exact` to false.
|
||||
pub fn glyph_dimensions(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
exact: bool)
|
||||
-> Result<GlyphDimensions, ()> {
|
||||
let core_graphics_font = match self.core_graphics_fonts.get(&font_instance.font_key) {
|
||||
None => return Err(()),
|
||||
Some(core_graphics_font) => core_graphics_font,
|
||||
};
|
||||
|
||||
let glyph = glyph_key.glyph_index as CGGlyph;
|
||||
let mut bounding_boxes = [CG_ZERO_RECT];
|
||||
let mut advances = [0];
|
||||
if !core_graphics_font.get_glyph_b_boxes(&[glyph], &mut bounding_boxes) ||
|
||||
!core_graphics_font.get_glyph_advances(&[glyph], &mut advances) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Vertical subpixel offsets.
|
||||
let subpixel_offset = Point2D::new(glyph_key.subpixel_offset.into(), 0.0);
|
||||
|
||||
// Round out to pixel boundaries.
|
||||
let units_per_em = core_graphics_font.get_units_per_em();
|
||||
let scale = (font_instance.size.to_f64_px() as CGFloat) / (units_per_em as CGFloat);
|
||||
let bounding_box =
|
||||
Rect::new(Point2D::new(bounding_boxes[0].origin.x,
|
||||
bounding_boxes[0].origin.y),
|
||||
Size2D::new(bounding_boxes[0].size.width,
|
||||
bounding_boxes[0].size.height)).scale(scale, scale);
|
||||
let mut lower_left = Point2D::new(bounding_box.origin.x.floor() as i32,
|
||||
bounding_box.origin.y.floor() as i32);
|
||||
let mut upper_right = Point2D::new((bounding_box.origin.x + bounding_box.size.width +
|
||||
subpixel_offset.x).ceil() as i32,
|
||||
(bounding_box.origin.y + bounding_box.size.height +
|
||||
subpixel_offset.y).ceil() as i32);
|
||||
|
||||
// Core Graphics performs font dilation to expand the outlines a bit. As of High Sierra,
|
||||
// the values seem to be 1.21% in the X direction and 1.5125% in the Y direction. Make sure
|
||||
// that there's enough room to account for this. We round the values up to 2% to account
|
||||
// for the possibility that Apple might tweak this later.
|
||||
if !exact {
|
||||
let font_dilation_radius = (font_instance.size.to_f32_px() *
|
||||
FONT_DILATION_AMOUNT * 0.5).ceil() as i32;
|
||||
lower_left += Vector2D::new(-font_dilation_radius, -font_dilation_radius);
|
||||
upper_right += Vector2D::new(font_dilation_radius, font_dilation_radius);
|
||||
}
|
||||
|
||||
Ok(GlyphDimensions {
|
||||
origin: lower_left,
|
||||
size: Size2D::new((upper_right.x - lower_left.x) as u32,
|
||||
(upper_right.y - lower_left.y) as u32),
|
||||
advance: advances[0] as f32,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a list of path commands that represent the given glyph in the given font.
|
||||
pub fn glyph_outline(&mut self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||
-> Result<GlyphOutline, ()> {
|
||||
let core_text_font = try!(self.ensure_core_text_font(font_instance));
|
||||
let path = try!(core_text_font.create_path_for_glyph(glyph_key.glyph_index as CGGlyph,
|
||||
&CG_AFFINE_TRANSFORM_IDENTITY));
|
||||
|
||||
let mut builder = vec![];
|
||||
path.apply(&|element| {
|
||||
let points = element.points();
|
||||
match element.element_type {
|
||||
CGPathElementType::MoveToPoint => {
|
||||
builder.push(PathEvent::MoveTo(convert_point(&points[0])))
|
||||
}
|
||||
CGPathElementType::AddLineToPoint => {
|
||||
builder.push(PathEvent::LineTo(convert_point(&points[0])))
|
||||
}
|
||||
CGPathElementType::AddQuadCurveToPoint => {
|
||||
builder.push(PathEvent::QuadraticTo(convert_point(&points[0]),
|
||||
convert_point(&points[1])))
|
||||
}
|
||||
CGPathElementType::AddCurveToPoint => {
|
||||
builder.push(PathEvent::CubicTo(convert_point(&points[0]),
|
||||
convert_point(&points[1]),
|
||||
convert_point(&points[2])))
|
||||
}
|
||||
CGPathElementType::CloseSubpath => builder.push(PathEvent::Close),
|
||||
}
|
||||
});
|
||||
|
||||
return Ok(GlyphOutline {
|
||||
events: builder,
|
||||
});
|
||||
|
||||
fn convert_point(core_graphics_point: &CGPoint) -> Point2D<f32> {
|
||||
Point2D::new(core_graphics_point.x as f32, core_graphics_point.y as f32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses the native Core Graphics library to rasterize a glyph on CPU.
|
||||
///
|
||||
/// Pathfinder uses this for reference testing.
|
||||
///
|
||||
/// If `exact` is true, then the glyph image will have precisely the size specified by the font
|
||||
/// designer. Because some font libraries, such as Core Graphics, perform modifications to the
|
||||
/// glyph outlines, to ensure the entire outline fits it is best to pass false for `exact`.
|
||||
pub fn rasterize_glyph_with_native_rasterizer(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
exact: bool)
|
||||
-> Result<GlyphImage, ()> {
|
||||
let core_graphics_font = match self.core_graphics_fonts.get(&font_instance.font_key) {
|
||||
None => return Err(()),
|
||||
Some(core_graphics_font) => core_graphics_font,
|
||||
};
|
||||
|
||||
let dimensions = try!(self.glyph_dimensions(font_instance, glyph_key, exact));
|
||||
|
||||
// TODO(pcwalton): Add support for non-subpixel render modes.
|
||||
let bitmap_context_flags = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;
|
||||
|
||||
let mut core_graphics_context =
|
||||
CGContext::create_bitmap_context(None,
|
||||
dimensions.size.width as usize,
|
||||
dimensions.size.height as usize,
|
||||
8,
|
||||
dimensions.size.width as usize * 4,
|
||||
&CGColorSpace::create_device_rgb(),
|
||||
bitmap_context_flags);
|
||||
|
||||
// TODO(pcwalton): Add support for non-subpixel render modes.
|
||||
let (antialias, smooth, bg_color) = (true, true, 1.0);
|
||||
|
||||
// Use subpixel positioning. But don't let Core Graphics quantize, because we do that
|
||||
// ourselves.
|
||||
core_graphics_context.set_allows_font_subpixel_positioning(true);
|
||||
core_graphics_context.set_should_subpixel_position_fonts(true);
|
||||
core_graphics_context.set_allows_font_subpixel_quantization(false);
|
||||
core_graphics_context.set_should_subpixel_quantize_fonts(false);
|
||||
|
||||
// Set up antialiasing flags.
|
||||
core_graphics_context.set_allows_font_smoothing(smooth);
|
||||
core_graphics_context.set_should_smooth_fonts(smooth);
|
||||
core_graphics_context.set_allows_antialiasing(antialias);
|
||||
core_graphics_context.set_should_antialias(antialias);
|
||||
|
||||
// Set up the background.
|
||||
core_graphics_context.set_rgb_fill_color(bg_color, bg_color, bg_color, bg_color);
|
||||
core_graphics_context.fill_rect(CGRect {
|
||||
origin: CG_ZERO_POINT,
|
||||
size: CGSize {
|
||||
width: dimensions.size.width as CGFloat,
|
||||
height: dimensions.size.height as CGFloat,
|
||||
},
|
||||
});
|
||||
|
||||
// Set up the text color.
|
||||
core_graphics_context.set_rgb_fill_color(0.0, 0.0, 0.0, 1.0);
|
||||
core_graphics_context.set_text_drawing_mode(CGTextDrawingMode::CGTextFill);
|
||||
|
||||
// Set up the font.
|
||||
core_graphics_context.set_font(core_graphics_font);
|
||||
core_graphics_context.set_font_size(font_instance.size.to_f64_px() as CGFloat);
|
||||
|
||||
// Compute the rasterization origin.
|
||||
// TODO(pcwalton): Vertical subpixel positioning.
|
||||
let subpixel_offset = Point2D::new(glyph_key.subpixel_offset.into(), 0.0);
|
||||
let origin = CGPoint {
|
||||
x: -dimensions.origin.x as CGFloat + subpixel_offset.x,
|
||||
y: -dimensions.origin.y as CGFloat,
|
||||
};
|
||||
|
||||
// Draw the glyph, and extract the pixels.
|
||||
core_graphics_context.show_glyphs_at_positions(&[glyph_key.glyph_index as CGGlyph],
|
||||
&[origin]);
|
||||
let mut pixels = core_graphics_context.data().to_vec();
|
||||
|
||||
// Swap BGRA to RGBA.
|
||||
for pixel in pixels.chunks_mut(4) {
|
||||
let (b, r) = (pixel[0], pixel[2]);
|
||||
pixel[0] = r;
|
||||
pixel[2] = b;
|
||||
}
|
||||
|
||||
// Return the image.
|
||||
Ok(GlyphImage {
|
||||
dimensions: dimensions,
|
||||
pixels: pixels,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<FK> FontInstance<FK> where FK: Clone {
|
||||
fn instantiate(&self, core_graphics_font: &CGFont) -> Result<CTFont, ()> {
|
||||
Ok(core_text::font::new_from_CGFont(core_graphics_font, self.size.to_f64_px()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlyphOutline {
|
||||
events: Vec<PathEvent>,
|
||||
}
|
||||
|
||||
impl GlyphOutline {
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Cloned<Iter<PathEvent>> {
|
||||
self.events.iter().cloned()
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
// pathfinder/font-renderer/src/directwrite/com.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Utility types for Microsoft COM.
|
||||
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use uuid;
|
||||
use winapi::{E_NOINTERFACE, E_POINTER, GUID, HRESULT, IUnknown, REFIID, S_OK, ULONG};
|
||||
|
||||
pub struct PathfinderComPtr<T> {
|
||||
ptr: *mut T,
|
||||
}
|
||||
|
||||
impl<T> PathfinderComPtr<T> {
|
||||
#[inline]
|
||||
pub unsafe fn new(ptr: *mut T) -> PathfinderComPtr<T> {
|
||||
PathfinderComPtr {
|
||||
ptr: ptr,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_raw(self) -> *mut T {
|
||||
let ptr = self.ptr;
|
||||
mem::forget(self);
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for PathfinderComPtr<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> PathfinderComPtr<T> {
|
||||
unsafe {
|
||||
(*(self.ptr as *mut IUnknown)).AddRef();
|
||||
}
|
||||
PathfinderComPtr {
|
||||
ptr: self.ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for PathfinderComPtr<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(*(self.ptr as *mut IUnknown)).Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for PathfinderComPtr<T> {
|
||||
type Target = *mut T;
|
||||
#[inline]
|
||||
fn deref(&self) -> &*mut T {
|
||||
&self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PathfinderCoclass {
|
||||
type InterfaceVtable: 'static;
|
||||
fn interface_guid() -> &'static GUID;
|
||||
fn vtable() -> &'static Self::InterfaceVtable;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PathfinderComObject<DerivedClass> where DerivedClass: PathfinderCoclass {
|
||||
vtable: &'static DerivedClass::InterfaceVtable,
|
||||
ref_count: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<DerivedClass> PathfinderComObject<DerivedClass> where DerivedClass: PathfinderCoclass {
|
||||
#[inline]
|
||||
pub unsafe fn construct() -> PathfinderComObject<DerivedClass> {
|
||||
PathfinderComObject {
|
||||
vtable: DerivedClass::vtable(),
|
||||
ref_count: AtomicUsize::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn AddRef(this: *mut IUnknown) -> ULONG {
|
||||
let this = this as *mut PathfinderComObject<DerivedClass>;
|
||||
((*this).ref_count.fetch_add(1, Ordering::SeqCst) + 1) as ULONG
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn Release(this: *mut IUnknown) -> ULONG {
|
||||
let this = this as *mut PathfinderComObject<DerivedClass>;
|
||||
let new_ref_count = (*this).ref_count.fetch_sub(1, Ordering::SeqCst) - 1;
|
||||
if new_ref_count == 0 {
|
||||
drop(Box::from_raw(this))
|
||||
}
|
||||
new_ref_count as ULONG
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn QueryInterface(this: *mut IUnknown,
|
||||
riid: REFIID,
|
||||
object: *mut *mut c_void)
|
||||
-> HRESULT {
|
||||
if object.is_null() {
|
||||
return E_POINTER
|
||||
}
|
||||
if guids_are_equal(&*riid, &uuid::IID_IUnknown) ||
|
||||
guids_are_equal(&*riid, DerivedClass::interface_guid()) {
|
||||
*object = this as *mut c_void;
|
||||
return S_OK
|
||||
}
|
||||
*object = ptr::null_mut();
|
||||
E_NOINTERFACE
|
||||
}
|
||||
}
|
||||
|
||||
fn guids_are_equal(a: &GUID, b: &GUID) -> bool {
|
||||
a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4
|
||||
}
|
|
@ -1,669 +0,0 @@
|
|||
// pathfinder/font-renderer/src/directwrite/mod.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Font loading using a hybrid of Windows DirectWrite and FreeType for hinting.
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals)]
|
||||
|
||||
use dwrite;
|
||||
use euclid::{Point2D, Size2D};
|
||||
use kernel32;
|
||||
use lyon_path::PathEvent;
|
||||
use std::collections::BTreeMap;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Cloned;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::slice::{self, Iter};
|
||||
use std::sync::Arc;
|
||||
use uuid::IID_ID2D1SimplifiedGeometrySink;
|
||||
use winapi::winerror::{self, S_OK};
|
||||
use winapi::{self, BOOL, D2D1_BEZIER_SEGMENT, D2D1_FIGURE_BEGIN, D2D1_FIGURE_END};
|
||||
use winapi::{D2D1_FIGURE_END_CLOSED, D2D1_FILL_MODE, D2D1_PATH_SEGMENT, D2D1_POINT_2F};
|
||||
use winapi::{DWRITE_FONT_METRICS, DWRITE_GLYPH_METRICS, E_BOUNDS, E_INVALIDARG, FALSE, FILETIME};
|
||||
use winapi::{FLOAT, GUID, HRESULT, ID2D1SimplifiedGeometrySinkVtbl, IDWriteFactory};
|
||||
use winapi::{IDWriteFontCollectionLoader, IDWriteFontCollectionLoaderVtbl, IDWriteFontFace};
|
||||
use winapi::{IDWriteFontFile, IDWriteFontFileEnumerator, IDWriteFontFileEnumeratorVtbl};
|
||||
use winapi::{IDWriteFontFileLoader, IDWriteFontFileLoaderVtbl, IDWriteFontFileStream};
|
||||
use winapi::{IDWriteFontFileStreamVtbl, IDWriteGeometrySink, IUnknown, IUnknownVtbl, TRUE, UINT16};
|
||||
use winapi::{UINT32, UINT64, UINT};
|
||||
|
||||
use self::com::{PathfinderCoclass, PathfinderComObject};
|
||||
pub use self::com::{PathfinderComPtr};
|
||||
use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey};
|
||||
|
||||
mod com;
|
||||
|
||||
DEFINE_GUID! {
|
||||
IID_IDWriteFactory, 0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48
|
||||
}
|
||||
DEFINE_GUID! {
|
||||
IID_IDWriteFontCollectionLoader,
|
||||
0xcca920e4, 0x52f0, 0x492b, 0xbf, 0xa8, 0x29, 0xc7, 0x2e, 0xe0, 0xa4, 0x68
|
||||
}
|
||||
DEFINE_GUID! {
|
||||
IID_IDWriteFontFileEnumerator,
|
||||
0x72755049, 0x5ff7, 0x435d, 0x83, 0x48, 0x4b, 0xe9, 0x7c, 0xfa, 0x6c, 0x7c
|
||||
}
|
||||
DEFINE_GUID! {
|
||||
IID_IDWriteFontFileLoader,
|
||||
0x727cad4e, 0xd6af, 0x4c9e, 0x8a, 0x08, 0xd6, 0x95, 0xb1, 0x1c, 0xaa, 0x49
|
||||
}
|
||||
DEFINE_GUID! {
|
||||
IID_IDWriteFontFileStream,
|
||||
0x6d4865fe, 0x0ab8, 0x4d91, 0x8f, 0x62, 0x5d, 0xd6, 0xbe, 0x34, 0xa3, 0xe0
|
||||
}
|
||||
|
||||
static PATHFINDER_FONT_COLLECTION_KEY: [u8; 17] = *b"MEMORY_COLLECTION";
|
||||
static PATHFINDER_FONT_FILE_KEY: [u8; 11] = *b"MEMORY_FILE";
|
||||
|
||||
/// An object that loads and renders fonts using Windows DirectWrite.
|
||||
pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
dwrite_factory: PathfinderComPtr<IDWriteFactory>,
|
||||
dwrite_font_faces: BTreeMap<FK, PathfinderComPtr<IDWriteFontFace>>,
|
||||
}
|
||||
|
||||
impl<FK> FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
/// Creates a new font context instance.
|
||||
pub fn new() -> Result<FontContext<FK>, ()> {
|
||||
unsafe {
|
||||
let mut factory: *mut IDWriteFactory = ptr::null_mut();
|
||||
if !winerror::SUCCEEDED(dwrite::DWriteCreateFactory(winapi::DWRITE_FACTORY_TYPE_SHARED,
|
||||
&IID_IDWriteFactory,
|
||||
&mut factory as *mut *mut _ as
|
||||
*mut *mut IUnknown)) {
|
||||
return Err(())
|
||||
}
|
||||
let factory = PathfinderComPtr::new(factory);
|
||||
|
||||
Ok(FontContext {
|
||||
dwrite_factory: factory,
|
||||
dwrite_font_faces: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads an OpenType font from memory.
|
||||
///
|
||||
/// `font_key` is a handle that is used to refer to the font later. If this context has already
|
||||
/// loaded a font with the same font key, nothing is done, and `Ok` is returned.
|
||||
///
|
||||
/// `bytes` is the raw OpenType data (i.e. the contents of the `.otf` or `.ttf` file on disk).
|
||||
///
|
||||
/// `font_index` is the index of the font within the collection, if `bytes` refers to a
|
||||
/// collection (`.ttc`).
|
||||
pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, _: u32)
|
||||
-> Result<(), ()> {
|
||||
unsafe {
|
||||
let font_file_loader = PathfinderFontFileLoader::new(bytes.clone());
|
||||
|
||||
let result = (**self.dwrite_factory).RegisterFontFileLoader(
|
||||
font_file_loader.clone().into_raw() as *mut IDWriteFontFileLoader);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut font_file = ptr::null_mut();
|
||||
let result = (**self.dwrite_factory).CreateCustomFontFileReference(
|
||||
PATHFINDER_FONT_FILE_KEY.as_ptr() as *const c_void,
|
||||
PATHFINDER_FONT_FILE_KEY.len() as UINT,
|
||||
font_file_loader.clone().into_raw() as *mut IDWriteFontFileLoader,
|
||||
&mut font_file);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
let font_file = PathfinderComPtr::new(font_file);
|
||||
|
||||
let font_collection_loader = PathfinderFontCollectionLoader::new(font_file);
|
||||
|
||||
let result = (**self.dwrite_factory).RegisterFontCollectionLoader(
|
||||
font_collection_loader.clone().into_raw() as *mut IDWriteFontCollectionLoader);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut font_collection = ptr::null_mut();
|
||||
let result = (**self.dwrite_factory).CreateCustomFontCollection(
|
||||
font_collection_loader.clone().into_raw() as *mut IDWriteFontCollectionLoader,
|
||||
PATHFINDER_FONT_COLLECTION_KEY.as_ptr() as *const c_void,
|
||||
PATHFINDER_FONT_COLLECTION_KEY.len() as UINT32,
|
||||
&mut font_collection);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
let font_collection = PathfinderComPtr::new(font_collection);
|
||||
|
||||
let mut font_family = ptr::null_mut();
|
||||
let result = (**font_collection).GetFontFamily(0, &mut font_family);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
let font_family = PathfinderComPtr::new(font_family);
|
||||
|
||||
let mut font = ptr::null_mut();
|
||||
let result = (**font_family).GetFont(0, &mut font);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
let font = PathfinderComPtr::new(font);
|
||||
|
||||
let mut font_face = ptr::null_mut();
|
||||
let result = (**font).CreateFontFace(&mut font_face);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
let font_face = PathfinderComPtr::new(font_face);
|
||||
|
||||
let result = (**self.dwrite_factory).UnregisterFontCollectionLoader(
|
||||
font_collection_loader.into_raw() as *mut IDWriteFontCollectionLoader);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let result = (**self.dwrite_factory).UnregisterFontFileLoader(
|
||||
font_file_loader.into_raw() as *mut IDWriteFontFileLoader);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
self.dwrite_font_faces.insert((*font_key).clone(), font_face);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads an OpenType font from a COM `IDWriteFontFace` handle.
|
||||
pub fn add_native_font<H>(&mut self, font_key: &FK, handle: H) -> Result<(), ()>
|
||||
where H: Into<PathfinderComPtr<IDWriteFontFace>>
|
||||
{
|
||||
match self.dwrite_font_faces.entry((*font_key).clone()) {
|
||||
Entry::Occupied(_) => Ok(()),
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(handle.into());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unloads the font with the given font key from memory.
|
||||
///
|
||||
/// If the font isn't loaded, does nothing.
|
||||
#[inline]
|
||||
pub fn delete_font(&mut self, font_key: &FK) {
|
||||
self.dwrite_font_faces.remove(font_key);
|
||||
}
|
||||
|
||||
/// Returns the dimensions of the given glyph in the given font.
|
||||
///
|
||||
/// If `exact` is true, then the raw outline extents as specified by the font designer are
|
||||
/// returned. These may differ from the extents when rendered on screen, because some font
|
||||
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
||||
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
||||
/// set `exact` to false.
|
||||
pub fn glyph_dimensions(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
_exact: bool)
|
||||
-> Result<GlyphDimensions, ()> {
|
||||
|
||||
let mut metrics: DWRITE_GLYPH_METRICS = unsafe { mem::zeroed() };
|
||||
|
||||
unsafe {
|
||||
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
||||
None => return Err(()),
|
||||
Some(font_face) => (*font_face).clone(),
|
||||
};
|
||||
|
||||
let glyph_index = glyph_key.glyph_index as UINT16;
|
||||
|
||||
let result = (**font_face).GetDesignGlyphMetrics(&glyph_index, 1, &mut metrics, FALSE);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
let character_width = metrics.advanceWidth as i32 - metrics.rightSideBearing - metrics.leftSideBearing;
|
||||
let character_height = metrics.advanceHeight as i32 - metrics.topSideBearing - metrics.bottomSideBearing;
|
||||
|
||||
Ok(GlyphDimensions {
|
||||
advance: metrics.advanceWidth as f32,
|
||||
origin: Point2D::new(metrics.leftSideBearing, metrics.bottomSideBearing),
|
||||
size: Size2D::new(character_width as u32,
|
||||
character_height as u32),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a list of path commands that represent the given glyph in the given font.
|
||||
pub fn glyph_outline(&mut self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||
-> Result<GlyphOutline, ()> {
|
||||
unsafe {
|
||||
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
||||
None => return Err(()),
|
||||
Some(font_face) => (*font_face).clone(),
|
||||
};
|
||||
|
||||
let mut metrics: DWRITE_FONT_METRICS = mem::zeroed();
|
||||
(**font_face).GetMetrics(&mut metrics);
|
||||
|
||||
let geometry_sink = PathfinderGeometrySink::new();
|
||||
let glyph_index = glyph_key.glyph_index as UINT16;
|
||||
|
||||
let result =
|
||||
(**font_face).GetGlyphRunOutline(metrics.designUnitsPerEm as FLOAT,
|
||||
&glyph_index,
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
1,
|
||||
FALSE,
|
||||
FALSE,
|
||||
*geometry_sink as *mut IDWriteGeometrySink);
|
||||
if !winerror::SUCCEEDED(result) {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
Ok(GlyphOutline {
|
||||
events: mem::replace(&mut (**geometry_sink).commands, vec![]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rasterize_glyph_with_native_rasterizer(&self,
|
||||
_font_instance: &FontInstance<FK>,
|
||||
_glyph_key: &GlyphKey,
|
||||
_exact: bool)
|
||||
-> Result<GlyphImage, ()> {
|
||||
// TODO(pcwalton)
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PathfinderFontCollectionLoader {
|
||||
object: PathfinderComObject<PathfinderFontCollectionLoader>,
|
||||
font_file: PathfinderComPtr<IDWriteFontFile>,
|
||||
}
|
||||
|
||||
static PATHFINDER_FONT_COLLECTION_LOADER_VTABLE:
|
||||
IDWriteFontCollectionLoaderVtbl = IDWriteFontCollectionLoaderVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
AddRef: PathfinderComObject::<PathfinderFontCollectionLoader>::AddRef,
|
||||
Release: PathfinderComObject::<PathfinderFontCollectionLoader>::Release,
|
||||
QueryInterface: PathfinderComObject::<PathfinderFontCollectionLoader>::QueryInterface,
|
||||
},
|
||||
CreateEnumeratorFromKey: PathfinderFontCollectionLoader::CreateEnumeratorFromKey,
|
||||
};
|
||||
|
||||
impl PathfinderCoclass for PathfinderFontCollectionLoader {
|
||||
type InterfaceVtable = IDWriteFontCollectionLoaderVtbl;
|
||||
fn interface_guid() -> &'static GUID { &IID_IDWriteFontCollectionLoader }
|
||||
fn vtable() -> &'static IDWriteFontCollectionLoaderVtbl {
|
||||
&PATHFINDER_FONT_COLLECTION_LOADER_VTABLE
|
||||
}
|
||||
}
|
||||
|
||||
impl PathfinderFontCollectionLoader {
|
||||
#[inline]
|
||||
fn new(font_file: PathfinderComPtr<IDWriteFontFile>)
|
||||
-> PathfinderComPtr<PathfinderFontCollectionLoader> {
|
||||
unsafe {
|
||||
PathfinderComPtr::new(Box::into_raw(Box::new(PathfinderFontCollectionLoader {
|
||||
object: PathfinderComObject::construct(),
|
||||
font_file: font_file,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn CreateEnumeratorFromKey(
|
||||
this: *mut IDWriteFontCollectionLoader,
|
||||
factory: *mut IDWriteFactory,
|
||||
_: *const c_void,
|
||||
_: UINT32,
|
||||
font_file_enumerator: *mut *mut IDWriteFontFileEnumerator)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontCollectionLoader;
|
||||
|
||||
let factory = PathfinderComPtr::new(factory);
|
||||
let font_file = (*this).font_file.clone();
|
||||
let new_font_file_enumerator = PathfinderFontFileEnumerator::new(factory, font_file);
|
||||
|
||||
*font_file_enumerator = new_font_file_enumerator.into_raw() as
|
||||
*mut IDWriteFontFileEnumerator;
|
||||
S_OK
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PathfinderFontFileEnumerator {
|
||||
object: PathfinderComObject<PathfinderFontFileEnumerator>,
|
||||
factory: PathfinderComPtr<IDWriteFactory>,
|
||||
font_file: PathfinderComPtr<IDWriteFontFile>,
|
||||
state: PathfinderFontFileEnumeratorState,
|
||||
}
|
||||
|
||||
static PATHFINDER_FONT_FILE_ENUMERATOR_VTABLE:
|
||||
IDWriteFontFileEnumeratorVtbl = IDWriteFontFileEnumeratorVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
AddRef: PathfinderComObject::<PathfinderFontFileEnumerator>::AddRef,
|
||||
Release: PathfinderComObject::<PathfinderFontFileEnumerator>::Release,
|
||||
QueryInterface: PathfinderComObject::<PathfinderFontFileEnumerator>::QueryInterface,
|
||||
},
|
||||
GetCurrentFontFile: PathfinderFontFileEnumerator::GetCurrentFontFile,
|
||||
MoveNext: PathfinderFontFileEnumerator::MoveNext,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum PathfinderFontFileEnumeratorState {
|
||||
Start,
|
||||
AtFontFile,
|
||||
End,
|
||||
}
|
||||
|
||||
impl PathfinderCoclass for PathfinderFontFileEnumerator {
|
||||
type InterfaceVtable = IDWriteFontFileEnumeratorVtbl;
|
||||
fn interface_guid() -> &'static GUID { &IID_IDWriteFontFileEnumerator }
|
||||
fn vtable() -> &'static IDWriteFontFileEnumeratorVtbl {
|
||||
&PATHFINDER_FONT_FILE_ENUMERATOR_VTABLE
|
||||
}
|
||||
}
|
||||
|
||||
impl PathfinderFontFileEnumerator {
|
||||
#[inline]
|
||||
fn new(factory: PathfinderComPtr<IDWriteFactory>, font_file: PathfinderComPtr<IDWriteFontFile>)
|
||||
-> PathfinderComPtr<PathfinderFontFileEnumerator> {
|
||||
unsafe {
|
||||
PathfinderComPtr::new(Box::into_raw(Box::new(PathfinderFontFileEnumerator {
|
||||
object: PathfinderComObject::construct(),
|
||||
factory: factory,
|
||||
font_file: font_file,
|
||||
state: PathfinderFontFileEnumeratorState::Start,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn GetCurrentFontFile(this: *mut IDWriteFontFileEnumerator,
|
||||
font_file: *mut *mut IDWriteFontFile)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileEnumerator;
|
||||
if (*this).state != PathfinderFontFileEnumeratorState::AtFontFile {
|
||||
*font_file = ptr::null_mut();
|
||||
return E_BOUNDS
|
||||
}
|
||||
|
||||
*font_file = (*this).font_file.clone().into_raw();
|
||||
S_OK
|
||||
}
|
||||
|
||||
unsafe extern "system" fn MoveNext(this: *mut IDWriteFontFileEnumerator,
|
||||
has_current_file: *mut BOOL)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileEnumerator;
|
||||
match (*this).state {
|
||||
PathfinderFontFileEnumeratorState::Start => {
|
||||
(*this).state = PathfinderFontFileEnumeratorState::AtFontFile;
|
||||
*has_current_file = TRUE;
|
||||
}
|
||||
PathfinderFontFileEnumeratorState::AtFontFile => {
|
||||
(*this).state = PathfinderFontFileEnumeratorState::End;
|
||||
*has_current_file = FALSE;
|
||||
}
|
||||
PathfinderFontFileEnumeratorState::End => *has_current_file = FALSE,
|
||||
}
|
||||
S_OK
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PathfinderFontFileLoader {
|
||||
object: PathfinderComObject<PathfinderFontFileLoader>,
|
||||
buffer: Arc<Vec<u8>>,
|
||||
}
|
||||
|
||||
static PATHFINDER_FONT_FILE_LOADER_VTABLE: IDWriteFontFileLoaderVtbl = IDWriteFontFileLoaderVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
AddRef: PathfinderComObject::<PathfinderFontFileLoader>::AddRef,
|
||||
Release: PathfinderComObject::<PathfinderFontFileLoader>::Release,
|
||||
QueryInterface: PathfinderComObject::<PathfinderFontFileLoader>::QueryInterface,
|
||||
},
|
||||
CreateStreamFromKey: PathfinderFontFileLoader::CreateStreamFromKey,
|
||||
};
|
||||
|
||||
impl PathfinderCoclass for PathfinderFontFileLoader {
|
||||
type InterfaceVtable = IDWriteFontFileLoaderVtbl;
|
||||
fn interface_guid() -> &'static GUID { &IID_IDWriteFontFileLoader }
|
||||
fn vtable() -> &'static IDWriteFontFileLoaderVtbl { &PATHFINDER_FONT_FILE_LOADER_VTABLE }
|
||||
}
|
||||
|
||||
impl PathfinderFontFileLoader {
|
||||
#[inline]
|
||||
fn new(buffer: Arc<Vec<u8>>) -> PathfinderComPtr<PathfinderFontFileLoader> {
|
||||
unsafe {
|
||||
PathfinderComPtr::new(Box::into_raw(Box::new(PathfinderFontFileLoader {
|
||||
object: PathfinderComObject::construct(),
|
||||
buffer: buffer,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn CreateStreamFromKey(
|
||||
this: *mut IDWriteFontFileLoader,
|
||||
font_file_reference_key: *const c_void,
|
||||
font_file_reference_key_size: UINT32,
|
||||
font_file_stream: *mut *mut IDWriteFontFileStream)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileLoader;
|
||||
let font_file_reference = slice::from_raw_parts(font_file_reference_key as *const u8,
|
||||
font_file_reference_key_size as usize);
|
||||
if font_file_reference != PATHFINDER_FONT_FILE_KEY {
|
||||
*font_file_stream = ptr::null_mut();
|
||||
return E_INVALIDARG
|
||||
}
|
||||
|
||||
*font_file_stream = PathfinderFontFileStream::new((*this).buffer.clone()).into_raw() as
|
||||
*mut IDWriteFontFileStream;
|
||||
S_OK
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PathfinderFontFileStream {
|
||||
object: PathfinderComObject<PathfinderFontFileStream>,
|
||||
buffer: Arc<Vec<u8>>,
|
||||
creation_time: UINT64,
|
||||
}
|
||||
|
||||
static PATHFINDER_FONT_FILE_STREAM_VTABLE: IDWriteFontFileStreamVtbl = IDWriteFontFileStreamVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
AddRef: PathfinderComObject::<PathfinderFontFileStream>::AddRef,
|
||||
Release: PathfinderComObject::<PathfinderFontFileStream>::Release,
|
||||
QueryInterface: PathfinderComObject::<PathfinderFontFileStream>::QueryInterface,
|
||||
},
|
||||
GetFileSize: PathfinderFontFileStream::GetFileSize,
|
||||
GetLastWriteTime: PathfinderFontFileStream::GetLastWriteTime,
|
||||
ReadFileFragment: PathfinderFontFileStream::ReadFileFragment,
|
||||
ReleaseFileFragment: PathfinderFontFileStream::ReleaseFileFragment,
|
||||
};
|
||||
|
||||
impl PathfinderCoclass for PathfinderFontFileStream {
|
||||
type InterfaceVtable = IDWriteFontFileStreamVtbl;
|
||||
fn interface_guid() -> &'static GUID { &IID_IDWriteFontFileStream }
|
||||
fn vtable() -> &'static IDWriteFontFileStreamVtbl { &PATHFINDER_FONT_FILE_STREAM_VTABLE }
|
||||
}
|
||||
|
||||
impl PathfinderFontFileStream {
|
||||
#[inline]
|
||||
fn new(buffer: Arc<Vec<u8>>) -> PathfinderComPtr<PathfinderFontFileStream> {
|
||||
unsafe {
|
||||
let mut now = FILETIME {
|
||||
dwLowDateTime: 0,
|
||||
dwHighDateTime: 0,
|
||||
};
|
||||
kernel32::GetSystemTimeAsFileTime(&mut now);
|
||||
|
||||
PathfinderComPtr::new(Box::into_raw(Box::new(PathfinderFontFileStream {
|
||||
object: PathfinderComObject::construct(),
|
||||
buffer: buffer,
|
||||
creation_time: ((now.dwHighDateTime as UINT64) << 32) |
|
||||
(now.dwLowDateTime as UINT64),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn GetFileSize(this: *mut IDWriteFontFileStream, file_size: *mut UINT64)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileStream;
|
||||
*file_size = (*this).buffer.len() as UINT64;
|
||||
S_OK
|
||||
}
|
||||
|
||||
unsafe extern "system" fn GetLastWriteTime(this: *mut IDWriteFontFileStream,
|
||||
last_write_time: *mut UINT64)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileStream;
|
||||
*last_write_time = (*this).creation_time;
|
||||
S_OK
|
||||
}
|
||||
|
||||
unsafe extern "system" fn ReadFileFragment(this: *mut IDWriteFontFileStream,
|
||||
fragment_start: *mut *const c_void,
|
||||
file_offset: UINT64,
|
||||
fragment_size: UINT64,
|
||||
fragment_context: *mut *mut c_void)
|
||||
-> HRESULT {
|
||||
let this = this as *mut PathfinderFontFileStream;
|
||||
let buffer_length = (*this).buffer.len() as u64;
|
||||
if file_offset > buffer_length || file_offset + fragment_size > buffer_length {
|
||||
return E_BOUNDS
|
||||
}
|
||||
|
||||
let ptr = (*(*this).buffer).as_ptr().offset(file_offset as isize) as *const c_void;
|
||||
*fragment_start = ptr;
|
||||
*fragment_context = ptr as *mut c_void;
|
||||
(*(this as *mut IUnknown)).AddRef();
|
||||
S_OK
|
||||
}
|
||||
|
||||
unsafe extern "system" fn ReleaseFileFragment(this: *mut IDWriteFontFileStream,
|
||||
_: *mut c_void) {
|
||||
let this = this as *mut PathfinderFontFileStream;
|
||||
(*(this as *mut IUnknown)).Release();
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PathfinderGeometrySink {
|
||||
object: PathfinderComObject<PathfinderGeometrySink>,
|
||||
commands: Vec<PathEvent>,
|
||||
}
|
||||
|
||||
static PATHFINDER_GEOMETRY_SINK_VTABLE: ID2D1SimplifiedGeometrySinkVtbl =
|
||||
ID2D1SimplifiedGeometrySinkVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
AddRef: PathfinderComObject::<PathfinderGeometrySink>::AddRef,
|
||||
Release: PathfinderComObject::<PathfinderGeometrySink>::Release,
|
||||
QueryInterface: PathfinderComObject::<PathfinderGeometrySink>::QueryInterface,
|
||||
},
|
||||
AddBeziers: PathfinderGeometrySink::AddBeziers,
|
||||
AddLines: PathfinderGeometrySink::AddLines,
|
||||
BeginFigure: PathfinderGeometrySink::BeginFigure,
|
||||
Close: PathfinderGeometrySink::Close,
|
||||
EndFigure: PathfinderGeometrySink::EndFigure,
|
||||
SetFillMode: PathfinderGeometrySink::SetFillMode,
|
||||
SetSegmentFlags: PathfinderGeometrySink::SetSegmentFlags,
|
||||
};
|
||||
|
||||
impl PathfinderCoclass for PathfinderGeometrySink {
|
||||
type InterfaceVtable = ID2D1SimplifiedGeometrySinkVtbl;
|
||||
fn interface_guid() -> &'static GUID { unsafe { &IID_ID2D1SimplifiedGeometrySink } }
|
||||
fn vtable() -> &'static ID2D1SimplifiedGeometrySinkVtbl { &PATHFINDER_GEOMETRY_SINK_VTABLE }
|
||||
}
|
||||
|
||||
impl PathfinderGeometrySink {
|
||||
#[inline]
|
||||
fn new() -> PathfinderComPtr<PathfinderGeometrySink> {
|
||||
unsafe {
|
||||
PathfinderComPtr::new(Box::into_raw(Box::new(PathfinderGeometrySink {
|
||||
object: PathfinderComObject::construct(),
|
||||
commands: vec![],
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn AddBeziers(this: *mut IDWriteGeometrySink,
|
||||
beziers: *const D2D1_BEZIER_SEGMENT,
|
||||
beziers_count: UINT) {
|
||||
let this = this as *mut PathfinderGeometrySink;
|
||||
let beziers = slice::from_raw_parts(beziers, beziers_count as usize);
|
||||
for bezier in beziers {
|
||||
let control_point_0 =
|
||||
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point1);
|
||||
let control_point_1 =
|
||||
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point2);
|
||||
let endpoint =
|
||||
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point3);
|
||||
(*this).commands.push(PathEvent::CubicTo(control_point_0, control_point_1, endpoint));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn AddLines(this: *mut IDWriteGeometrySink,
|
||||
points: *const D2D1_POINT_2F,
|
||||
points_count: UINT) {
|
||||
let this = this as *mut PathfinderGeometrySink;
|
||||
let points = slice::from_raw_parts(points, points_count as usize);
|
||||
for point in points {
|
||||
let point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&point);
|
||||
(*this).commands.push(PathEvent::LineTo(point))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn BeginFigure(this: *mut IDWriteGeometrySink,
|
||||
start_point: D2D1_POINT_2F,
|
||||
_: D2D1_FIGURE_BEGIN) {
|
||||
let this = this as *mut PathfinderGeometrySink;
|
||||
let start_point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&start_point);
|
||||
(*this).commands.push(PathEvent::MoveTo(start_point))
|
||||
}
|
||||
|
||||
unsafe extern "system" fn Close(_: *mut IDWriteGeometrySink) -> HRESULT {
|
||||
S_OK
|
||||
}
|
||||
|
||||
unsafe extern "system" fn EndFigure(this: *mut IDWriteGeometrySink,
|
||||
figure_end: D2D1_FIGURE_END) {
|
||||
let this = this as *mut PathfinderGeometrySink;
|
||||
if figure_end == D2D1_FIGURE_END_CLOSED {
|
||||
(*this).commands.push(PathEvent::Close)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn SetFillMode(_: *mut IDWriteGeometrySink, _: D2D1_FILL_MODE) {
|
||||
// TODO(pcwalton)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn SetSegmentFlags(_: *mut IDWriteGeometrySink, _: D2D1_PATH_SEGMENT) {
|
||||
// Should be unused.
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn d2d_point_2f_to_flipped_f32_point(point: &D2D1_POINT_2F) -> Point2D<f32> {
|
||||
Point2D::new(point.x, -point.y)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlyphOutline {
|
||||
events: Vec<PathEvent>,
|
||||
}
|
||||
|
||||
impl GlyphOutline {
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Cloned<Iter<PathEvent>> {
|
||||
self.events.iter().cloned()
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// pathfinder/font-renderer/src/freetype/fixed.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Utilities for FreeType 26.6 fixed-point numbers.
|
||||
|
||||
use app_units::Au;
|
||||
use freetype_sys::freetype::FT_F26Dot6;
|
||||
|
||||
pub trait FromFtF26Dot6 {
|
||||
fn from_ft_f26dot6(value: FT_F26Dot6) -> Self;
|
||||
}
|
||||
|
||||
impl FromFtF26Dot6 for f32 {
|
||||
fn from_ft_f26dot6(value: FT_F26Dot6) -> f32 {
|
||||
(value as f32) / 64.0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToFtF26Dot6 {
|
||||
fn to_ft_f26dot6(self) -> FT_F26Dot6;
|
||||
}
|
||||
|
||||
impl ToFtF26Dot6 for f32 {
|
||||
fn to_ft_f26dot6(self) -> FT_F26Dot6 {
|
||||
(self * 64.0 + 0.5) as FT_F26Dot6
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFtF26Dot6 for f64 {
|
||||
fn to_ft_f26dot6(self) -> FT_F26Dot6 {
|
||||
(self * 64.0 + 0.5) as FT_F26Dot6
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFtF26Dot6 for Au {
|
||||
fn to_ft_f26dot6(self) -> FT_F26Dot6 {
|
||||
self.to_f64_px().to_ft_f26dot6()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn floor(n: FT_F26Dot6) -> FT_F26Dot6 {
|
||||
n & !0x3f
|
||||
}
|
|
@ -1,387 +0,0 @@
|
|||
// pathfinder/font-renderer/src/freetype/mod.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Font loading using FreeType.
|
||||
|
||||
use euclid::{Point2D, Size2D, Vector2D};
|
||||
use freetype_sys::freetype::{FT_BBox, FT_Bitmap, FT_Done_Face, FT_F26Dot6, FT_Face, FT_Glyph_Format};
|
||||
use freetype_sys::freetype::{FT_GlyphSlot, FT_Init_FreeType, FT_Int32, FT_LcdFilter};
|
||||
use freetype_sys::freetype::{FT_LOAD_NO_HINTING, FT_Library, FT_Library_SetLcdFilter};
|
||||
use freetype_sys::freetype::{FT_Load_Glyph, FT_Long, FT_New_Face, FT_New_Memory_Face};
|
||||
use freetype_sys::freetype::{FT_Outline_Get_CBox, FT_Outline_Translate, FT_Pixel_Mode};
|
||||
use freetype_sys::freetype::{FT_Render_Glyph, FT_Render_Mode, FT_Set_Char_Size, FT_UInt};
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::ffi::CString;
|
||||
use std::hash::Hash;
|
||||
use std::mem;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
use self::fixed::{FromFtF26Dot6, ToFtF26Dot6};
|
||||
use self::outline::Outline;
|
||||
use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey};
|
||||
|
||||
mod fixed;
|
||||
mod outline;
|
||||
|
||||
pub type GlyphOutline<'a> = Outline<'a>;
|
||||
|
||||
// Default to no hinting.
|
||||
//
|
||||
// TODO(pcwalton): Make this configurable.
|
||||
const GLYPH_LOAD_FLAGS: FT_Int32 = FT_LOAD_NO_HINTING as FT_Int32;
|
||||
|
||||
const DPI: u32 = 72;
|
||||
|
||||
const STEM_DARKENING_AMOUNT: f32 = 0.02;
|
||||
|
||||
/// An object that loads and renders fonts using the FreeType library.
|
||||
pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
library: FT_Library,
|
||||
faces: BTreeMap<FK, Face>,
|
||||
}
|
||||
|
||||
unsafe impl<FK> Send for FontContext<FK> where FK: Clone + Hash + Eq + Ord + Send {}
|
||||
|
||||
impl<FK> FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||
/// Creates a new font context instance.
|
||||
pub fn new() -> Result<FontContext<FK>, ()> {
|
||||
let mut library: FT_Library = ptr::null_mut();
|
||||
unsafe {
|
||||
let result = FT_Init_FreeType(&mut library);
|
||||
if result != 0 {
|
||||
return Err(())
|
||||
}
|
||||
}
|
||||
Ok(FontContext {
|
||||
library: library,
|
||||
faces: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Loads an OpenType font from memory.
|
||||
///
|
||||
/// `font_key` is a handle that is used to refer to the font later. If this context has already
|
||||
/// loaded a font with the same font key, nothing is done, and `Ok` is returned.
|
||||
///
|
||||
/// `bytes` is the raw OpenType data (i.e. the contents of the `.otf` or `.ttf` file on disk).
|
||||
///
|
||||
/// `font_index` is the index of the font within the collection, if `bytes` refers to a
|
||||
/// collection (`.ttc`).
|
||||
pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, font_index: u32)
|
||||
-> Result<(), ()> {
|
||||
match self.faces.entry((*font_key).clone()) {
|
||||
Entry::Occupied(_) => Ok(()),
|
||||
Entry::Vacant(entry) => {
|
||||
unsafe {
|
||||
let mut face_ptr = ptr::null_mut();
|
||||
let result = FT_New_Memory_Face(self.library,
|
||||
bytes.as_ptr(),
|
||||
bytes.len() as FT_Long,
|
||||
font_index as FT_Long,
|
||||
&mut face_ptr);
|
||||
let mut face = Face {
|
||||
face: face_ptr,
|
||||
bytes: Some(bytes),
|
||||
};
|
||||
if result == 0 && !face.face.is_null() {
|
||||
entry.insert(face);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_native_font<H>(&mut self, font_key: &FK, handle: H) -> Result<(), ()>
|
||||
where H: Into<FontDescriptor> {
|
||||
match self.faces.entry((*font_key).clone()) {
|
||||
Entry::Occupied(_) => Ok(()),
|
||||
Entry::Vacant(entry) => {
|
||||
unsafe {
|
||||
let descriptor: FontDescriptor = handle.into();
|
||||
let mut face_ptr = ptr::null_mut();
|
||||
let pathname = CString::new(descriptor.pathname
|
||||
.as_os_str()
|
||||
.as_bytes()).unwrap();
|
||||
let result = FT_New_Face(self.library,
|
||||
pathname.as_ptr(),
|
||||
descriptor.index as FT_Long,
|
||||
&mut face_ptr);
|
||||
let mut face = Face {
|
||||
face: face_ptr,
|
||||
bytes: None,
|
||||
};
|
||||
if result == 0 && !face.face.is_null() {
|
||||
entry.insert(face);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unloads the font with the given font key from memory.
|
||||
///
|
||||
/// If the font isn't loaded, does nothing.
|
||||
pub fn delete_font(&mut self, font_key: &FK) {
|
||||
self.faces.remove(font_key);
|
||||
}
|
||||
|
||||
/// Returns the dimensions of the given glyph in the given font.
|
||||
///
|
||||
/// If `exact` is true, then the raw outline extents as specified by the font designer are
|
||||
/// returned. These may differ from the extents when rendered on screen, because some font
|
||||
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
||||
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
||||
/// set `exact` to false.
|
||||
pub fn glyph_dimensions(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
exact: bool)
|
||||
-> Result<GlyphDimensions, ()> {
|
||||
self.load_glyph(font_instance, glyph_key).ok_or(()).and_then(|glyph_slot| {
|
||||
self.glyph_dimensions_from_slot(font_instance, glyph_key, glyph_slot, exact)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn glyph_outline<'a>(&'a self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||
-> Result<GlyphOutline<'a>, ()> {
|
||||
self.load_glyph(font_instance, glyph_key).ok_or(()).map(|glyph_slot| {
|
||||
unsafe {
|
||||
GlyphOutline::new(&(*glyph_slot).outline)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Uses the FreeType library to rasterize a glyph on CPU.
|
||||
///
|
||||
/// If `exact` is true, then the raw outline extents as specified by the font designer are
|
||||
/// returned. These may differ from the extents when rendered on screen, because some font
|
||||
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
||||
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
||||
/// set `exact` to false.
|
||||
pub fn rasterize_glyph_with_native_rasterizer(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
_: bool)
|
||||
-> Result<GlyphImage, ()> {
|
||||
// Load the glyph.
|
||||
let slot = match self.load_glyph(font_instance, glyph_key) {
|
||||
None => return Err(()),
|
||||
Some(slot) => slot,
|
||||
};
|
||||
|
||||
// Get the subpixel offset.
|
||||
let subpixel_offset: Vector2D<FT_F26Dot6> =
|
||||
Vector2D::new(f32::to_ft_f26dot6(glyph_key.subpixel_offset.into()), 0);
|
||||
|
||||
// Move the outline curves to be at the origin, taking the subpixel positioning into
|
||||
// account.
|
||||
unsafe {
|
||||
let outline = &(*slot).outline;
|
||||
let mut control_box: FT_BBox = mem::uninitialized();
|
||||
FT_Outline_Get_CBox(outline, &mut control_box);
|
||||
FT_Outline_Translate(
|
||||
outline,
|
||||
subpixel_offset.x - fixed::floor(control_box.xMin + subpixel_offset.x),
|
||||
subpixel_offset.y - fixed::floor(control_box.yMin + subpixel_offset.y));
|
||||
}
|
||||
|
||||
// Set the LCD filter.
|
||||
//
|
||||
// TODO(pcwalton): Non-subpixel AA.
|
||||
unsafe {
|
||||
FT_Library_SetLcdFilter(self.library, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
|
||||
}
|
||||
|
||||
// Render the glyph.
|
||||
//
|
||||
// TODO(pcwalton): Non-subpixel AA.
|
||||
unsafe {
|
||||
FT_Render_Glyph(slot, FT_Render_Mode::FT_RENDER_MODE_LCD);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Make sure that the pixel mode is LCD.
|
||||
//
|
||||
// TODO(pcwalton): Non-subpixel AA.
|
||||
let bitmap: *const FT_Bitmap = &(*slot).bitmap;
|
||||
if (*bitmap).pixel_mode as u32 != FT_Pixel_Mode::FT_PIXEL_MODE_LCD as u32 {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
debug_assert_eq!((*bitmap).width % 3, 0);
|
||||
let pixel_size = Size2D::new((*bitmap).width as u32 / 3, (*bitmap).rows as u32);
|
||||
let pixel_origin = Point2D::new((*slot).bitmap_left, (*slot).bitmap_top);
|
||||
|
||||
// Allocate the RGBA8 buffer.
|
||||
let src_stride = (*bitmap).pitch as usize;
|
||||
let dest_stride = pixel_size.width as usize;
|
||||
let src_area = src_stride * ((*bitmap).rows as usize);
|
||||
let dest_area = pixel_size.area() as usize;
|
||||
let mut dest_pixels: Vec<u32> = vec![0; dest_area];
|
||||
let src_pixels = slice::from_raw_parts((*bitmap).buffer, src_area);
|
||||
|
||||
// Convert to RGBA8.
|
||||
for y in 0..(pixel_size.height as usize) {
|
||||
let dest_row = &mut dest_pixels[(y * dest_stride)..((y + 1) * dest_stride)];
|
||||
let src_row = &src_pixels[(y * src_stride)..((y + 1) * src_stride)];
|
||||
for (x, dest) in dest_row.iter_mut().enumerate() {
|
||||
*dest = ((255 - src_row[x * 3 + 2]) as u32) |
|
||||
(((255 - src_row[x * 3 + 1]) as u32) << 8) |
|
||||
(((255 - src_row[x * 3 + 0]) as u32) << 16) |
|
||||
(0xff << 24)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result.
|
||||
Ok(GlyphImage {
|
||||
dimensions: GlyphDimensions {
|
||||
origin: pixel_origin,
|
||||
size: pixel_size,
|
||||
advance: f32::from_ft_f26dot6((*slot).metrics.horiAdvance),
|
||||
},
|
||||
pixels: convert_vec_u32_to_vec_u8(dest_pixels),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn load_glyph(&self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||
-> Option<FT_GlyphSlot> {
|
||||
let face = match self.faces.get(&font_instance.font_key) {
|
||||
None => return None,
|
||||
Some(face) => face,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let point_size = font_instance.size.to_ft_f26dot6();
|
||||
FT_Set_Char_Size(face.face, point_size, 0, DPI, 0);
|
||||
|
||||
if FT_Load_Glyph(face.face, glyph_key.glyph_index as FT_UInt, GLYPH_LOAD_FLAGS) != 0 {
|
||||
return None
|
||||
}
|
||||
|
||||
let slot = (*face.face).glyph;
|
||||
if (*slot).format != FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE {
|
||||
return None
|
||||
}
|
||||
|
||||
Some(slot)
|
||||
}
|
||||
}
|
||||
|
||||
fn glyph_dimensions_from_slot(&self,
|
||||
font_instance: &FontInstance<FK>,
|
||||
glyph_key: &GlyphKey,
|
||||
glyph_slot: FT_GlyphSlot,
|
||||
exact: bool)
|
||||
-> Result<GlyphDimensions, ()> {
|
||||
unsafe {
|
||||
let metrics = &(*glyph_slot).metrics;
|
||||
|
||||
// This matches what WebRender does.
|
||||
if metrics.horiAdvance == 0 {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let bounding_box = self.bounding_box_from_slot(font_instance, glyph_key, glyph_slot);
|
||||
|
||||
let mut lower_left = Point2D::new(f26dot6_to_i32_rounding_up(bounding_box.xMin),
|
||||
f26dot6_to_i32_rounding_up(bounding_box.yMin));
|
||||
let mut upper_right = Point2D::new(f26dot6_to_i32_rounding_up(bounding_box.xMax),
|
||||
f26dot6_to_i32_rounding_up(bounding_box.yMax));
|
||||
|
||||
// Account for stem darkening. Round up to be conservative.
|
||||
if !exact {
|
||||
let stem_darkening_radius = (font_instance.size.to_f32_px() *
|
||||
STEM_DARKENING_AMOUNT * 0.5).ceil() as i32;
|
||||
lower_left += Vector2D::new(-stem_darkening_radius, -stem_darkening_radius);
|
||||
upper_right += Vector2D::new(stem_darkening_radius, stem_darkening_radius);
|
||||
}
|
||||
|
||||
Ok(GlyphDimensions {
|
||||
origin: lower_left,
|
||||
size: Size2D::new((upper_right.x - lower_left.x) as u32,
|
||||
(upper_right.y - lower_left.y) as u32),
|
||||
advance: f32::from_ft_f26dot6(metrics.horiAdvance) /
|
||||
(*(*glyph_slot).face).units_per_EM as f32 *
|
||||
font_instance.size.to_f32_px(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the bounding box for a glyph, accounting for subpixel positioning as appropriate.
|
||||
//
|
||||
// TODO(pcwalton): Subpixel positioning.
|
||||
fn bounding_box_from_slot(&self, _: &FontInstance<FK>, _: &GlyphKey, glyph_slot: FT_GlyphSlot)
|
||||
-> FT_BBox {
|
||||
let mut bounding_box: FT_BBox;
|
||||
unsafe {
|
||||
bounding_box = mem::zeroed();
|
||||
FT_Outline_Get_CBox(&(*glyph_slot).outline, &mut bounding_box);
|
||||
};
|
||||
|
||||
// Outset the box to device pixel boundaries. This matches what WebRender does.
|
||||
bounding_box.xMin = fixed::floor(bounding_box.xMin);
|
||||
bounding_box.yMin = fixed::floor(bounding_box.yMin);
|
||||
bounding_box.xMax = fixed::floor(bounding_box.xMax + 0x3f);
|
||||
bounding_box.yMax = fixed::floor(bounding_box.yMax + 0x3f);
|
||||
|
||||
bounding_box
|
||||
}
|
||||
}
|
||||
|
||||
struct Face {
|
||||
face: FT_Face,
|
||||
#[allow(dead_code)]
|
||||
bytes: Option<Arc<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl Drop for Face {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FT_Done_Face(self.face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FontDescriptor {
|
||||
pub pathname: PathBuf,
|
||||
pub index: u32,
|
||||
}
|
||||
|
||||
impl FontDescriptor {
|
||||
#[inline]
|
||||
pub fn new(pathname: PathBuf, index: u32) -> FontDescriptor {
|
||||
FontDescriptor {
|
||||
pathname: pathname,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn convert_vec_u32_to_vec_u8(mut input: Vec<u32>) -> Vec<u8> {
|
||||
let (ptr, len, cap) = (input.as_mut_ptr(), input.len(), input.capacity());
|
||||
mem::forget(input);
|
||||
Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4)
|
||||
}
|
||||
|
||||
fn f26dot6_to_i32_rounding_up(x: FT_F26Dot6) -> i32 {
|
||||
((x + (1 << 5) - 1) >> 6) as i32
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
// pathfinder/font-renderer/src/freetype/outline.rs
|
||||
//
|
||||
// Copyright © 2017 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 euclid::Point2D;
|
||||
use freetype_sys::freetype::{FT_Outline, FT_Vector};
|
||||
use lyon_path::iterator::PathIterator;
|
||||
use lyon_path::{PathEvent, PathState};
|
||||
|
||||
const FREETYPE_POINT_ON_CURVE: i8 = 0x01;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Outline<'a> {
|
||||
outline: &'a FT_Outline,
|
||||
}
|
||||
|
||||
impl<'a> Outline<'a> {
|
||||
#[inline]
|
||||
pub unsafe fn new(outline: &FT_Outline) -> Outline {
|
||||
Outline {
|
||||
outline: outline,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> OutlineStream {
|
||||
unsafe {
|
||||
OutlineStream::new(self.outline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutlineStream<'a> {
|
||||
outline: &'a FT_Outline,
|
||||
point_index: u16,
|
||||
contour_index: u16,
|
||||
state: PathState,
|
||||
first_point_index_of_contour: bool,
|
||||
}
|
||||
|
||||
impl<'a> OutlineStream<'a> {
|
||||
#[inline]
|
||||
pub unsafe fn new(outline: &FT_Outline) -> OutlineStream {
|
||||
OutlineStream {
|
||||
outline: outline,
|
||||
point_index: 0,
|
||||
contour_index: 0,
|
||||
state: PathState::new(),
|
||||
first_point_index_of_contour: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn current_position_and_tag(&self) -> (Point2D<f32>, i8) {
|
||||
unsafe {
|
||||
let point_offset = self.point_index as isize;
|
||||
let position = ft_vector_to_f32(*self.outline.points.offset(point_offset));
|
||||
let tag = *self.outline.tags.offset(point_offset);
|
||||
(position, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OutlineStream<'a> {
|
||||
type Item = PathEvent;
|
||||
|
||||
fn next(&mut self) -> Option<PathEvent> {
|
||||
unsafe {
|
||||
let mut control_point_position: Option<Point2D<f32>> = None;
|
||||
loop {
|
||||
if self.contour_index == self.outline.n_contours as u16 {
|
||||
return None
|
||||
}
|
||||
|
||||
let last_point_index_in_current_contour =
|
||||
*self.outline.contours.offset(self.contour_index as isize) as u16;
|
||||
if self.point_index == last_point_index_in_current_contour + 1 {
|
||||
if let Some(control_point_position) = control_point_position {
|
||||
let event = PathEvent::QuadraticTo(control_point_position,
|
||||
self.state.first);
|
||||
self.state.path_event(event);
|
||||
return Some(event)
|
||||
}
|
||||
|
||||
self.contour_index += 1;
|
||||
self.first_point_index_of_contour = true;
|
||||
self.state.close();
|
||||
return Some(PathEvent::Close)
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Approximate cubic curves with quadratics.
|
||||
let (position, tag) = self.current_position_and_tag();
|
||||
let point_on_curve = (tag & FREETYPE_POINT_ON_CURVE) != 0;
|
||||
|
||||
if self.first_point_index_of_contour {
|
||||
self.first_point_index_of_contour = false;
|
||||
self.point_index += 1;
|
||||
self.state.move_to(position);
|
||||
return Some(PathEvent::MoveTo(position));
|
||||
}
|
||||
|
||||
match (control_point_position, point_on_curve) {
|
||||
(Some(control_point_position), false) => {
|
||||
let on_curve_position = control_point_position.lerp(position, 0.5);
|
||||
let event = PathEvent::QuadraticTo(control_point_position,
|
||||
on_curve_position);
|
||||
self.state.path_event(event);
|
||||
return Some(event)
|
||||
}
|
||||
(Some(control_point_position), true) => {
|
||||
self.point_index += 1;
|
||||
let event = PathEvent::QuadraticTo(control_point_position, position);
|
||||
self.state.path_event(event);
|
||||
return Some(event)
|
||||
}
|
||||
(None, false) => {
|
||||
self.point_index += 1;
|
||||
control_point_position = Some(position);
|
||||
}
|
||||
(None, true) => {
|
||||
self.point_index += 1;
|
||||
self.state.line_to(position);
|
||||
return Some(PathEvent::LineTo(position))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PathIterator for OutlineStream<'a> {
|
||||
#[inline]
|
||||
fn get_state(&self) -> &PathState {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ft_vector_to_f32(ft_vector: FT_Vector) -> Point2D<f32> {
|
||||
Point2D::new(ft_vector.x as f32 / 64.0, ft_vector.y as f32 / 64.0)
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
// pathfinder/font-renderer/src/lib.rs
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
|
||||
//! Reads outlines from OpenType fonts into Pathfinder path formats.
|
||||
//!
|
||||
//! Use this crate in conjunction with `pathfinder_partitioner` in order to create meshes for
|
||||
//! rendering.
|
||||
//!
|
||||
//! To reduce dependencies and to match the system as closely as possible, this crate uses the
|
||||
//! native OS font rendering infrastructure as much as it can. Backends are available for FreeType,
|
||||
//! Core Graphics/Quartz on macOS, and DirectWrite on Windows.
|
||||
|
||||
extern crate app_units;
|
||||
extern crate euclid;
|
||||
extern crate libc;
|
||||
extern crate lyon_path;
|
||||
extern crate serde;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
extern crate core_graphics as core_graphics_sys;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
extern crate core_text;
|
||||
|
||||
#[cfg(any(target_os = "linux", feature = "freetype-backend"))]
|
||||
extern crate freetype as freetype_sys;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
extern crate dwrite;
|
||||
#[cfg(target_os = "windows")]
|
||||
extern crate kernel32;
|
||||
#[cfg(target_os = "windows")]
|
||||
extern crate uuid;
|
||||
#[cfg(target_os = "windows")]
|
||||
#[macro_use(DEFINE_GUID)]
|
||||
extern crate winapi;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use self::directwrite::PathfinderComPtr;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use winapi::IDWriteFontFace;
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::{Point2D, Size2D};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(all(any(target_os = "macos", target_os = "ios"), not(feature = "freetype-backend")))]
|
||||
pub use core_graphics::{FontContext, GlyphOutline};
|
||||
#[cfg(all(target_os = "windows", not(feature = "freetype-backend")))]
|
||||
pub use directwrite::FontContext;
|
||||
#[cfg(any(target_os = "linux", feature = "freetype-backend"))]
|
||||
pub use freetype::FontContext;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub mod core_graphics;
|
||||
#[cfg(all(target_os = "windows", not(feature = "freetype-backend")))]
|
||||
mod directwrite;
|
||||
#[cfg(any(target_os = "linux", feature = "freetype-backend"))]
|
||||
pub mod freetype;
|
||||
|
||||
/// The number of subpixels that each pixel is divided into for the purposes of subpixel glyph
|
||||
/// positioning.
|
||||
///
|
||||
/// Right now, each glyph is snapped to the nearest quarter-pixel.
|
||||
pub const SUBPIXEL_GRANULARITY: u8 = 4;
|
||||
|
||||
/// A font at one specific size.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
|
||||
pub struct FontInstance<FK> where FK: Clone {
|
||||
/// The opaque font key that this font instance represents.
|
||||
pub font_key: FK,
|
||||
|
||||
/// The size of the font.
|
||||
///
|
||||
/// This is in app units (1/60 pixels) to eliminate floating point error.
|
||||
pub size: Au,
|
||||
}
|
||||
|
||||
impl<FK> FontInstance<FK> where FK: Clone {
|
||||
/// Creates a new instance of a font at the given size.
|
||||
#[inline]
|
||||
pub fn new(font_key: &FK, size: Au) -> FontInstance<FK> {
|
||||
FontInstance {
|
||||
font_key: (*font_key).clone(),
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A subpixel offset, from 0 to `SUBPIXEL_GRANULARITY`.
|
||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct SubpixelOffset(pub u8);
|
||||
|
||||
impl Into<f32> for SubpixelOffset {
|
||||
#[inline]
|
||||
fn into(self) -> f32 {
|
||||
self.0 as f32 / SUBPIXEL_GRANULARITY as f32
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for SubpixelOffset {
|
||||
#[inline]
|
||||
fn into(self) -> f64 {
|
||||
self.0 as f64 / SUBPIXEL_GRANULARITY as f64
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to the resolution-independent image of a single glyph in a single font.
|
||||
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GlyphKey {
|
||||
/// The OpenType glyph index.
|
||||
pub glyph_index: u32,
|
||||
/// The subpixel offset, from 0 to `SUBPIXEL_GRANULARITY`.
|
||||
pub subpixel_offset: SubpixelOffset,
|
||||
}
|
||||
|
||||
impl GlyphKey {
|
||||
/// Creates a new glyph key from the given index and subpixel offset.
|
||||
#[inline]
|
||||
pub fn new(glyph_index: u32, subpixel_offset: SubpixelOffset) -> GlyphKey {
|
||||
GlyphKey {
|
||||
glyph_index: glyph_index,
|
||||
subpixel_offset: subpixel_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolution-independent dimensions of a glyph, in font units.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GlyphDimensions {
|
||||
/// The origin of the glyph.
|
||||
pub origin: Point2D<i32>,
|
||||
/// The total size of the glyph.
|
||||
pub size: Size2D<u32>,
|
||||
/// The advance of the glyph: that is, the distance from this glyph to the next one.
|
||||
pub advance: f32,
|
||||
}
|
||||
|
||||
/// A bitmap image of a glyph.
|
||||
pub struct GlyphImage {
|
||||
/// The dimensions of this image.
|
||||
pub dimensions: GlyphDimensions,
|
||||
/// The actual pixels.
|
||||
///
|
||||
/// This is 8 bits per pixel grayscale when grayscale antialiasing is in use and 24 bits per
|
||||
/// pixel RGB when subpixel antialiasing is in use.
|
||||
pub pixels: Vec<u8>,
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
// pathfinder/font-renderer/src/tests.rs
|
||||
|
||||
use app_units::Au;
|
||||
use env_logger;
|
||||
use euclid::Size2D;
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use pathfinder_path_utils::{PathBuffer, Subpath};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::sync::Arc;
|
||||
use {FontContext, FontInstance, FontKey, GlyphDimensions, GlyphKey, SubpixelOffset};
|
||||
|
||||
static TEST_FONT_PATH: &'static str = "../resources/fonts/nimbus-sans/NimbusSanL-Regu.ttf";
|
||||
const TEST_FONT_SIZE: Au = Au(60 * 16);
|
||||
const TEST_GLYPH_ID: u32 = 68; // 'a'
|
||||
|
||||
const EXPECTED_GLYPH_ORIGIN: [i32; 2] = [0, 9];
|
||||
const EXPECTED_GLYPH_SIZE: [u32; 2] = [9, 9];
|
||||
const EXPECTED_GLYPH_ADVANCE: f32 = 9.0;
|
||||
|
||||
static EXPECTED_GLYPH_ENDPOINTS: [[f32; 2]; 34] = [
|
||||
[ 548.0, 77.0 ],
|
||||
[ 548.0, 10.0 ],
|
||||
[ 490.0, 0.0 ],
|
||||
[ 402.0, 82.0 ],
|
||||
[ 323.0, 24.0 ],
|
||||
[ 219.0, 0.0 ],
|
||||
[ 89.0, 44.0 ],
|
||||
[ 43.0, 158.0 ],
|
||||
[ 138.0, 301.0 ],
|
||||
[ 233.0, 324.0 ],
|
||||
[ 310.0, 333.0 ],
|
||||
[ 381.0, 353.0 ],
|
||||
[ 399.0, 392.0 ],
|
||||
[ 399.0, 414.0 ],
|
||||
[ 362.0, 476.0 ],
|
||||
[ 278.0, 494.0 ],
|
||||
[ 153.0, 400.0 ],
|
||||
[ 67.0, 400.0 ],
|
||||
[ 104.0, 512.0 ],
|
||||
[ 282.0, 576.0 ],
|
||||
[ 444.0, 529.0 ],
|
||||
[ 484.0, 430.0 ],
|
||||
[ 484.0, 117.0 ],
|
||||
[ 530.0, 75.0 ],
|
||||
[ 399.0, 289.0 ],
|
||||
[ 349.0, 273.0 ],
|
||||
[ 261.0, 258.0 ],
|
||||
[ 165.0, 228.0 ],
|
||||
[ 132.0, 161.0 ],
|
||||
[ 157.0, 101.0 ],
|
||||
[ 238.0, 75.0 ],
|
||||
[ 365.0, 124.0 ],
|
||||
[ 396.0, 169.0 ],
|
||||
[ 399.0, 193.0 ],
|
||||
];
|
||||
|
||||
static EXPECTED_GLYPH_CONTROL_POINTS: [[f32; 2]; 29] = [
|
||||
[ 512.0, 0.0 ],
|
||||
[ 410.0, 0.0 ],
|
||||
[ 362.0, 43.0 ],
|
||||
[ 276.0, 0.0 ],
|
||||
[ 137.0, 0.0 ],
|
||||
[ 43.0, 86.0 ],
|
||||
[ 43.0, 262.0 ],
|
||||
[ 169.0, 314.0 ],
|
||||
[ 241.0, 325.0 ],
|
||||
[ 365.0, 340.0 ],
|
||||
[ 398.0, 366.0 ],
|
||||
[ 399.0, 457.0 ],
|
||||
[ 330.0, 494.0 ],
|
||||
[ 163.0, 494.0 ],
|
||||
[ 70.0, 474.0 ],
|
||||
[ 160.0, 576.0 ],
|
||||
[ 394.0, 576.0 ],
|
||||
[ 484.0, 493.0 ],
|
||||
[ 484.0, 75.0 ],
|
||||
[ 537.0, 75.0 ],
|
||||
[ 377.0, 278.0 ],
|
||||
[ 325.0, 268.0 ],
|
||||
[ 195.0, 249.0 ],
|
||||
[ 132.0, 205.0 ],
|
||||
[ 132.0, 125.0 ],
|
||||
[ 183.0, 75.0 ],
|
||||
[ 313.0, 75.0 ],
|
||||
[ 390.0, 147.0 ],
|
||||
[ 399.0, 177.0 ],
|
||||
];
|
||||
|
||||
static EXPECTED_GLYPH_SUBPATHS: [Subpath; 2] = [
|
||||
Subpath {
|
||||
first_endpoint_index: 0,
|
||||
last_endpoint_index: 24,
|
||||
},
|
||||
Subpath {
|
||||
first_endpoint_index: 24,
|
||||
last_endpoint_index: 34,
|
||||
},
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_font_context_glyph_dimensions() {
|
||||
let mut font_context = FontContext::new().unwrap();
|
||||
|
||||
let font_key = FontKey::new();
|
||||
let mut bytes = vec![];
|
||||
File::open(TEST_FONT_PATH).unwrap().read_to_end(&mut bytes).unwrap();
|
||||
font_context.add_font_from_memory(&font_key, Arc::new(bytes), 0).unwrap();
|
||||
|
||||
let font_instance = FontInstance::new(&font_key, TEST_FONT_SIZE);
|
||||
let glyph_key = GlyphKey::new(TEST_GLYPH_ID, SubpixelOffset(0));
|
||||
let glyph_dimensions = font_context.glyph_dimensions(&font_instance, &glyph_key).unwrap();
|
||||
|
||||
assert_eq!(glyph_dimensions, GlyphDimensions {
|
||||
origin: EXPECTED_GLYPH_ORIGIN.into(),
|
||||
size: Size2D::new(EXPECTED_GLYPH_SIZE[0], EXPECTED_GLYPH_SIZE[1]),
|
||||
advance: EXPECTED_GLYPH_ADVANCE,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_font_context_glyph_outline() {
|
||||
drop(env_logger::init());
|
||||
|
||||
let mut font_context = FontContext::new().unwrap();
|
||||
|
||||
let font_key = FontKey::new();
|
||||
let mut bytes = vec![];
|
||||
File::open(TEST_FONT_PATH).unwrap().read_to_end(&mut bytes).unwrap();
|
||||
font_context.add_font_from_memory(&font_key, Arc::new(bytes), 0).unwrap();
|
||||
|
||||
let font_instance = FontInstance::new(&font_key, TEST_FONT_SIZE);
|
||||
let glyph_key = GlyphKey::new(TEST_GLYPH_ID, SubpixelOffset(0));
|
||||
let glyph_outline = font_context.glyph_outline(&font_instance, &glyph_key).unwrap();
|
||||
let mut glyph_outline_buffer = PathBuffer::new();
|
||||
glyph_outline_buffer.add_stream(glyph_outline);
|
||||
|
||||
info!("endpoints: {:#?}", glyph_outline_buffer.endpoints);
|
||||
info!("control points: {:#?}", glyph_outline_buffer.control_points);
|
||||
|
||||
assert_eq!(glyph_outline_buffer.endpoints.len(), EXPECTED_GLYPH_ENDPOINTS.len());
|
||||
for (expected_position, endpoint) in
|
||||
EXPECTED_GLYPH_ENDPOINTS.iter().zip(glyph_outline_buffer.endpoints.iter()) {
|
||||
let actual_position = endpoint.position;
|
||||
info!("expected endpoint: {:?} actual endpoint: {:?}", expected_position, actual_position);
|
||||
assert!(expected_position[0].approx_eq(&actual_position.x) &&
|
||||
expected_position[1].approx_eq(&actual_position.y));
|
||||
}
|
||||
|
||||
assert_eq!(glyph_outline_buffer.control_points.len(), EXPECTED_GLYPH_CONTROL_POINTS.len());
|
||||
for (expected_position, actual_position) in
|
||||
EXPECTED_GLYPH_CONTROL_POINTS.iter().zip(glyph_outline_buffer.control_points.iter()) {
|
||||
info!("expected control point: {:?} actual control point: {:?}",
|
||||
expected_position,
|
||||
actual_position);
|
||||
assert!(expected_position[0].approx_eq(&actual_position.x) &&
|
||||
expected_position[1].approx_eq(&actual_position.y));
|
||||
}
|
||||
|
||||
assert_eq!(glyph_outline_buffer.subpaths.len(), EXPECTED_GLYPH_SUBPATHS.len());
|
||||
for (expected_subpath, actual_subpath) in
|
||||
EXPECTED_GLYPH_SUBPATHS.iter().zip(glyph_outline_buffer.subpaths.iter()) {
|
||||
assert_eq!(expected_subpath.first_endpoint_index, actual_subpath.first_endpoint_index);
|
||||
assert_eq!(expected_subpath.last_endpoint_index, actual_subpath.last_endpoint_index);
|
||||
}
|
||||
}
|
|
@ -4,14 +4,12 @@ version = "0.2.0"
|
|||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
clap = "2.27"
|
||||
freetype = "0.4"
|
||||
lyon_path = "0.12"
|
||||
|
||||
[dependencies.pathfinder_font_renderer]
|
||||
path = "../../font-renderer"
|
||||
features = ["freetype"]
|
||||
[dependencies.font-kit]
|
||||
git = "https://github.com/pcwalton/font-kit"
|
||||
features = ["loader-freetype-default"]
|
||||
|
||||
[dependencies.pathfinder_partitioner]
|
||||
path = "../../partitioner"
|
||||
|
|
|
@ -23,77 +23,38 @@
|
|||
//! simple storage format for VBOs. To render these paths, you can directly upload these VBOs to
|
||||
//! the GPU and render them using the shaders provided.
|
||||
|
||||
extern crate app_units;
|
||||
extern crate clap;
|
||||
extern crate freetype;
|
||||
extern crate font_kit;
|
||||
extern crate lyon_path;
|
||||
extern crate pathfinder_font_renderer;
|
||||
extern crate pathfinder_partitioner;
|
||||
extern crate pathfinder_path_utils;
|
||||
|
||||
use app_units::Au;
|
||||
use clap::{App, Arg};
|
||||
use freetype::freetype::{FT_Init_FreeType, FT_New_Face};
|
||||
use font_kit::font::Font;
|
||||
use font_kit::hinting::HintingOptions;
|
||||
use lyon_path::PathEvent;
|
||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
||||
use pathfinder_font_renderer::{FontContext, FontInstance, GlyphKey, SubpixelOffset};
|
||||
use lyon_path::default::Path as LyonPath;
|
||||
use pathfinder_partitioner::FillRule;
|
||||
use pathfinder_partitioner::mesh_pack::MeshPack;
|
||||
use pathfinder_partitioner::partitioner::Partitioner;
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
const FONT_SIZE: f64 = 72.0;
|
||||
|
||||
fn convert_font(font_path: &Path, output_path: &Path) -> Result<(), ()> {
|
||||
let mut freetype_library = ptr::null_mut();
|
||||
let glyph_count;
|
||||
unsafe {
|
||||
if FT_Init_FreeType(&mut freetype_library) != 0 {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// TODO(pcwalton): Allow the user to select a face by index.
|
||||
let mut freetype_face = ptr::null_mut();
|
||||
let font_path = match font_path.to_str() {
|
||||
None => return Err(()),
|
||||
Some(font_path) => font_path,
|
||||
};
|
||||
let font_path = try!(CString::new(font_path).map_err(drop));
|
||||
if FT_New_Face(freetype_library, font_path.as_ptr(), 0, &mut freetype_face) != 0 {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
glyph_count = (*freetype_face).num_glyphs as u32;
|
||||
}
|
||||
|
||||
let mut font_data = vec![];
|
||||
let mut font_file = try!(File::open(font_path).map_err(drop));
|
||||
try!(font_file.read_to_end(&mut font_data).map_err(drop));
|
||||
|
||||
// TODO(pcwalton): Allow the user to select a face by index.
|
||||
let mut font_context = try!(FontContext::new());
|
||||
try!(font_context.add_font_from_memory(&(), Arc::new(font_data), 0));
|
||||
let font_instance = FontInstance {
|
||||
font_key: (),
|
||||
size: Au::from_f64_px(FONT_SIZE),
|
||||
};
|
||||
let font = try!(Font::from_path(font_path, 0).map_err(drop));
|
||||
let glyph_count = font.glyph_count();
|
||||
|
||||
let mut paths: Vec<(u16, Vec<PathEvent>)> = vec![];
|
||||
let mut mesh_pack = MeshPack::new();
|
||||
|
||||
for glyph_index in 0..glyph_count {
|
||||
let glyph_key = GlyphKey::new(glyph_index, SubpixelOffset(0));
|
||||
|
||||
let path = match font_context.glyph_outline(&font_instance, &glyph_key) {
|
||||
Ok(path) => path,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let mut path_builder = LyonPath::builder();
|
||||
if font.outline(glyph_index, HintingOptions::None, &mut path_builder).is_err() {
|
||||
continue
|
||||
}
|
||||
let path = path_builder.build();
|
||||
|
||||
let mut partitioner = Partitioner::new();
|
||||
|
||||
|
|
Loading…
Reference in New Issue