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)",
|
"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]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -109,6 +130,11 @@ name = "bitflags"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
@ -174,6 +200,18 @@ dependencies = [
|
||||||
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -193,35 +231,35 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.6.1"
|
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 = [
|
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)",
|
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.6.1"
|
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]]
|
[[package]]
|
||||||
name = "core-graphics"
|
name = "core-graphics"
|
||||||
version = "0.16.0"
|
version = "0.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-text"
|
name = "core-text"
|
||||||
version = "11.0.0"
|
version = "13.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"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)",
|
||||||
"core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dwrite-sys"
|
name = "dwrote"
|
||||||
version = "0.2.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/servo/dwrote-rs#28896a9346e60fdd7e3b929494bd7f7bfe0c2e72"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-build 0.1.1 (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]]
|
[[package]]
|
||||||
|
@ -306,6 +356,69 @@ dependencies = [
|
||||||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "fontsan"
|
name = "fontsan"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -331,8 +444,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freetype"
|
name = "freetype"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/servo/rust-freetype#e6ead0a811a604654d410c8ce9c43ee142329adc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -542,15 +663,6 @@ dependencies = [
|
||||||
"rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "language-tags"
|
name = "language-tags"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -623,6 +735,14 @@ name = "lzw"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -636,6 +756,15 @@ dependencies = [
|
||||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -713,6 +842,14 @@ dependencies = [
|
||||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "pango-sys"
|
name = "pango-sys"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -729,36 +866,13 @@ dependencies = [
|
||||||
name = "pathfinder"
|
name = "pathfinder"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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_partitioner 0.2.0",
|
||||||
"pathfinder_path_utils 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]]
|
[[package]]
|
||||||
name = "pathfinder_gfx_utils"
|
name = "pathfinder_gfx_utils"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -805,6 +919,7 @@ dependencies = [
|
||||||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"fontsan 0.4.0 (git+https://github.com/servo/fontsan.git)",
|
||||||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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_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)",
|
"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_partitioner 0.2.0",
|
||||||
"pathfinder_path_utils 0.2.0",
|
"pathfinder_path_utils 0.2.0",
|
||||||
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/rocket)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "safemem"
|
name = "safemem"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "scoped_threadpool"
|
name = "scoped_threadpool"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
@ -1093,6 +1220,25 @@ dependencies = [
|
||||||
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "servo-freetype-sys"
|
name = "servo-freetype-sys"
|
||||||
version = "4.0.3"
|
version = "4.0.3"
|
||||||
|
@ -1130,6 +1276,17 @@ dependencies = [
|
||||||
"unicode-xid 0.1.0 (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 = "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]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
@ -1257,15 +1414,6 @@ name = "utf8-ranges"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -1281,6 +1429,15 @@ name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
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)",
|
"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]]
|
[[package]]
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
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 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 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 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.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 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 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 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 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 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 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 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"
|
"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 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 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 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 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 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 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||||
"checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9"
|
"checksum core-foundation-sys 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||||
"checksum core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92801c908ea6301ae619ed842a72e01098085fc321b9c2f3f833dad555bba055"
|
"checksum core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
|
||||||
"checksum core-text 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "157ff38a92496dc676ce36d9124554e9ac66f1c1039f952690ac64f71cfa5968"
|
"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-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-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 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 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 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 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 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 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 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 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 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 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-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"
|
"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 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 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 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 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 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 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 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"
|
"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_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 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 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 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 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 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 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"
|
"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-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-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 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 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 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>"
|
"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 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 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 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 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 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 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 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_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 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 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 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 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 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 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 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 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"
|
"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 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 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 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 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 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 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.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 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-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 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"
|
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"font-renderer",
|
|
||||||
"gfx-utils",
|
"gfx-utils",
|
||||||
"partitioner",
|
"partitioner",
|
||||||
"path-utils",
|
"path-utils",
|
||||||
|
|
|
@ -5,8 +5,8 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
freetype = ["pathfinder_font_renderer/freetype"]
|
freetype = ["font-kit/loader-freetype-default"]
|
||||||
reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"]
|
reftests = ["rsvg", "cairo-rs", "font-kit/loader-freetype-default"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
|
@ -45,8 +45,8 @@ git = "https://github.com/SergioBenitez/rocket"
|
||||||
[dependencies.rocket_contrib]
|
[dependencies.rocket_contrib]
|
||||||
git = "https://github.com/SergioBenitez/rocket"
|
git = "https://github.com/SergioBenitez/rocket"
|
||||||
|
|
||||||
[dependencies.pathfinder_font_renderer]
|
[dependencies.font-kit]
|
||||||
path = "../../font-renderer"
|
git = "https://github.com/pcwalton/font-kit"
|
||||||
|
|
||||||
[dependencies.pathfinder_partitioner]
|
[dependencies.pathfinder_partitioner]
|
||||||
path = "../../partitioner"
|
path = "../../partitioner"
|
||||||
|
|
|
@ -15,12 +15,12 @@ extern crate app_units;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
|
extern crate font_kit;
|
||||||
extern crate fontsan;
|
extern crate fontsan;
|
||||||
extern crate image;
|
extern crate image;
|
||||||
extern crate lru_cache;
|
extern crate lru_cache;
|
||||||
extern crate lyon_geom;
|
extern crate lyon_geom;
|
||||||
extern crate lyon_path;
|
extern crate lyon_path;
|
||||||
extern crate pathfinder_font_renderer;
|
|
||||||
extern crate pathfinder_partitioner;
|
extern crate pathfinder_partitioner;
|
||||||
extern crate pathfinder_path_utils;
|
extern crate pathfinder_path_utils;
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
@ -36,15 +36,17 @@ extern crate cairo;
|
||||||
#[cfg(feature = "reftests")]
|
#[cfg(feature = "reftests")]
|
||||||
extern crate rsvg;
|
extern crate rsvg;
|
||||||
|
|
||||||
use app_units::Au;
|
|
||||||
use euclid::{Point2D, Transform2D};
|
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 image::{DynamicImage, ImageBuffer, ImageFormat, ImageRgba8};
|
||||||
use lru_cache::LruCache;
|
use lru_cache::LruCache;
|
||||||
use lyon_path::PathEvent;
|
use lyon_path::PathEvent;
|
||||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
||||||
use lyon_path::iterator::PathIter;
|
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::FillRule;
|
||||||
use pathfinder_partitioner::mesh_pack::MeshPack;
|
use pathfinder_partitioner::mesh_pack::MeshPack;
|
||||||
use pathfinder_partitioner::partitioner::Partitioner;
|
use pathfinder_partitioner::partitioner::Partitioner;
|
||||||
|
@ -58,14 +60,10 @@ use rocket_contrib::json::Json;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Cursor, Read};
|
use std::io::{self, Cursor, Read};
|
||||||
use std::path::{self, PathBuf};
|
use std::path::{self, PathBuf};
|
||||||
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use pathfinder_font_renderer::core_graphics;
|
|
||||||
|
|
||||||
#[cfg(feature = "reftests")]
|
#[cfg(feature = "reftests")]
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
#[cfg(feature = "reftests")]
|
#[cfg(feature = "reftests")]
|
||||||
|
@ -79,8 +77,6 @@ const MESH_PACK_CACHE_SIZE: usize = 16;
|
||||||
|
|
||||||
const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 5.0;
|
const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 5.0;
|
||||||
|
|
||||||
static NEXT_FONT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref MESH_PACK_CACHE: Mutex<LruCache<MeshPackCacheKey, PartitionResponder>> = {
|
static ref MESH_PACK_CACHE: Mutex<LruCache<MeshPackCacheKey, PartitionResponder>> = {
|
||||||
Mutex::new(LruCache::new(MESH_PACK_CACHE_SIZE))
|
Mutex::new(LruCache::new(MESH_PACK_CACHE_SIZE))
|
||||||
|
@ -267,15 +263,6 @@ struct PartitionSvgPathCommand {
|
||||||
values: Vec<f64>,
|
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 {
|
struct PathPartitioningResult {
|
||||||
encoded_data: Arc<Vec<u8>>,
|
encoded_data: Arc<Vec<u8>>,
|
||||||
time: Duration,
|
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>")]
|
#[post("/partition-font", format = "application/json", data = "<request>")]
|
||||||
fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionResponder, FontError> {
|
fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionResponder, FontError> {
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
|
@ -456,23 +418,10 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse glyph data.
|
// 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));
|
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() {
|
let font = match Font::from_bytes(otf_data, request.font_index) {
|
||||||
return Err(FontError::FontLoadingFailed)
|
Ok(font) => font,
|
||||||
}
|
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||||
|
|
||||||
let font_instance = FontInstance {
|
|
||||||
font_key: font_key,
|
|
||||||
size: Au::from_f64_px(request.point_size),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Read glyph info.
|
// Read glyph info.
|
||||||
|
@ -480,12 +429,12 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
|
||||||
let mut path_descriptors = vec![];
|
let mut path_descriptors = vec![];
|
||||||
|
|
||||||
for (glyph_index, glyph) in request.glyphs.iter().enumerate() {
|
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.
|
// This might fail; if so, just leave it blank.
|
||||||
match font_context.glyph_outline(&font_instance, &glyph_key) {
|
// FIXME(pcwalton): Should we add first-class support for transforms to `font-kit`?
|
||||||
Ok(glyph_outline) => {
|
let mut path_builder = lyon_path::default::Path::builder();
|
||||||
paths.push(Transform2DPathIter::new(glyph_outline.iter(),
|
match font.outline(glyph.id, HintingOptions::None, &mut path_builder) {
|
||||||
|
Ok(()) => {
|
||||||
|
paths.push(Transform2DPathIter::new(path_builder.build().into_iter(),
|
||||||
&glyph.transform).collect())
|
&glyph.transform).collect())
|
||||||
}
|
}
|
||||||
Err(_) => paths.push(vec![]),
|
Err(_) => paths.push(vec![]),
|
||||||
|
@ -601,39 +550,60 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
||||||
#[post("/render-reference/text", format = "application/json", data = "<request>")]
|
#[post("/render-reference/text", format = "application/json", data = "<request>")]
|
||||||
fn render_reference_text(request: Json<RenderTextReferenceRequest>)
|
fn render_reference_text(request: Json<RenderTextReferenceRequest>)
|
||||||
-> Result<ReferenceImage, FontError> {
|
-> Result<ReferenceImage, FontError> {
|
||||||
let font_key = FontKey::new();
|
|
||||||
let otf_data = try!(otf_data_from_request(&request.face));
|
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.
|
// Rasterize the glyph using the right rasterizer.
|
||||||
let glyph_image = match request.renderer {
|
let mut canvas;
|
||||||
|
match request.renderer {
|
||||||
ReferenceTextRenderer::FreeType => {
|
ReferenceTextRenderer::FreeType => {
|
||||||
let mut font_context =
|
let loader = match Font::from_bytes(otf_data, request.font_index) {
|
||||||
try!(FontContext::new().map_err(|_| FontError::FontLoadingFailed));
|
Ok(loader) => loader,
|
||||||
try!(font_context.add_font_from_memory(&font_key, otf_data, request.font_index)
|
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||||
.map_err(|_| FontError::FontLoadingFailed));
|
};
|
||||||
try!(font_context.rasterize_glyph_with_native_rasterizer(&font_instance,
|
let glyph_rect = try!(loader.raster_bounds(request.glyph,
|
||||||
&glyph_key,
|
request.point_size as f32,
|
||||||
true)
|
&Point2D::zero(),
|
||||||
.map_err(|_| FontError::RasterizationFailed))
|
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 => {
|
ReferenceTextRenderer::CoreGraphics => {
|
||||||
try!(rasterize_glyph_with_core_graphics(&font_key,
|
let loader = match loaders::core_text::Font::from_bytes(otf_data, request.font_index) {
|
||||||
request.font_index,
|
Ok(loader) => loader,
|
||||||
otf_data,
|
Err(_) => return Err(FontError::FontLoadingFailed),
|
||||||
&font_instance,
|
};
|
||||||
&glyph_key))
|
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(canvas.size.width,
|
||||||
let image_buffer = ImageBuffer::from_raw(dimensions.size.width,
|
canvas.size.height,
|
||||||
dimensions.size.height,
|
canvas.pixels).unwrap();
|
||||||
glyph_image.pixels).unwrap();
|
|
||||||
let reference_image = ReferenceImage {
|
let reference_image = ReferenceImage {
|
||||||
image: ImageRgba8(image_buffer),
|
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>"]
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
|
||||||
clap = "2.27"
|
clap = "2.27"
|
||||||
freetype = "0.4"
|
|
||||||
lyon_path = "0.12"
|
lyon_path = "0.12"
|
||||||
|
|
||||||
[dependencies.pathfinder_font_renderer]
|
[dependencies.font-kit]
|
||||||
path = "../../font-renderer"
|
git = "https://github.com/pcwalton/font-kit"
|
||||||
features = ["freetype"]
|
features = ["loader-freetype-default"]
|
||||||
|
|
||||||
[dependencies.pathfinder_partitioner]
|
[dependencies.pathfinder_partitioner]
|
||||||
path = "../../partitioner"
|
path = "../../partitioner"
|
||||||
|
|
|
@ -23,77 +23,38 @@
|
||||||
//! simple storage format for VBOs. To render these paths, you can directly upload these VBOs to
|
//! 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.
|
//! the GPU and render them using the shaders provided.
|
||||||
|
|
||||||
extern crate app_units;
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate freetype;
|
extern crate font_kit;
|
||||||
extern crate lyon_path;
|
extern crate lyon_path;
|
||||||
extern crate pathfinder_font_renderer;
|
|
||||||
extern crate pathfinder_partitioner;
|
extern crate pathfinder_partitioner;
|
||||||
extern crate pathfinder_path_utils;
|
extern crate pathfinder_path_utils;
|
||||||
|
|
||||||
use app_units::Au;
|
|
||||||
use clap::{App, Arg};
|
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::PathEvent;
|
||||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
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::FillRule;
|
||||||
use pathfinder_partitioner::mesh_pack::MeshPack;
|
use pathfinder_partitioner::mesh_pack::MeshPack;
|
||||||
use pathfinder_partitioner::partitioner::Partitioner;
|
use pathfinder_partitioner::partitioner::Partitioner;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process;
|
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<(), ()> {
|
fn convert_font(font_path: &Path, output_path: &Path) -> Result<(), ()> {
|
||||||
let mut freetype_library = ptr::null_mut();
|
let font = try!(Font::from_path(font_path, 0).map_err(drop));
|
||||||
let glyph_count;
|
let glyph_count = font.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 mut paths: Vec<(u16, Vec<PathEvent>)> = vec![];
|
let mut paths: Vec<(u16, Vec<PathEvent>)> = vec![];
|
||||||
let mut mesh_pack = MeshPack::new();
|
let mut mesh_pack = MeshPack::new();
|
||||||
|
|
||||||
for glyph_index in 0..glyph_count {
|
for glyph_index in 0..glyph_count {
|
||||||
let glyph_key = GlyphKey::new(glyph_index, SubpixelOffset(0));
|
let mut path_builder = LyonPath::builder();
|
||||||
|
if font.outline(glyph_index, HintingOptions::None, &mut path_builder).is_err() {
|
||||||
let path = match font_context.glyph_outline(&font_instance, &glyph_key) {
|
continue
|
||||||
Ok(path) => path,
|
}
|
||||||
Err(_) => continue,
|
let path = path_builder.build();
|
||||||
};
|
|
||||||
|
|
||||||
let mut partitioner = Partitioner::new();
|
let mut partitioner = Partitioner::new();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue