Remove `pathfinder_font_renderer` in favor of `font-kit`.

Closes #69.

Closes #84.
This commit is contained in:
Patrick Walton 2018-08-02 15:07:25 -07:00
parent a518cdac21
commit c6cc6e6fd8
15 changed files with 320 additions and 2321 deletions

317
Cargo.lock generated
View File

@ -67,6 +67,27 @@ dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
version = "0.6.0"
@ -109,6 +130,11 @@ name = "bitflags"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.3"
@ -174,6 +200,18 @@ dependencies = [
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cocoa"
version = "0.18.0"
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color_quant"
version = "1.0.1"
@ -193,35 +231,35 @@ dependencies = [
[[package]]
name = "core-foundation"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
dependencies = [
"core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-foundation-sys"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
[[package]]
name = "core-graphics"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "0.17.0"
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-text"
version = "11.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "13.0.0"
source = "git+https://github.com/servo/core-foundation-rs#540490a9094a756fb610ee157b064d48a7f180a8"
dependencies = [
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -266,18 +304,30 @@ dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dirs"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dwrite-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
name = "dwrote"
version = "0.5.0"
source = "git+https://github.com/servo/dwrote-rs#28896a9346e60fdd7e3b929494bd7f7bfe0c2e72"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -306,6 +356,69 @@ dependencies = [
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "expat-sys"
version = "2.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "float-ord"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "font-kit"
version = "0.1.0"
source = "git+https://github.com/pcwalton/font-kit#b6c001f663839961b70fcea1101398f589ce4fb9"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.18.0 (git+https://github.com/servo/core-foundation-rs)",
"core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)",
"core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)",
"core-text 13.0.0 (git+https://github.com/servo/core-foundation-rs)",
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.5.0 (git+https://github.com/servo/dwrote-rs)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.1 (git+https://github.com/servo/rust-freetype)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fontsan"
version = "0.4.0"
@ -331,8 +444,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "0.4.1"
source = "git+https://github.com/servo/rust-freetype#e6ead0a811a604654d410c8ce9c43ee142329adc"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -528,6 +641,14 @@ dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.2"
@ -542,15 +663,6 @@ dependencies = [
"rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "language-tags"
version = "0.2.2"
@ -623,6 +735,14 @@ name = "lzw"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
version = "0.1.6"
@ -636,6 +756,15 @@ dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memmap"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memoffset"
version = "0.2.1"
@ -713,6 +842,14 @@ dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pango-sys"
version = "0.5.0"
@ -729,36 +866,13 @@ dependencies = [
name = "pathfinder"
version = "0.2.0"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_font_renderer 0.5.0",
"pathfinder_partitioner 0.2.0",
"pathfinder_path_utils 0.2.0",
]
[[package]]
name = "pathfinder_font_renderer"
version = "0.5.0"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pathfinder_gfx_utils"
version = "0.2.0"
@ -805,6 +919,7 @@ dependencies = [
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)",
"fontsan 0.4.0 (git+https://github.com/servo/fontsan.git)",
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -812,7 +927,6 @@ dependencies = [
"lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_font_renderer 0.5.0",
"pathfinder_partitioner 0.2.0",
"pathfinder_path_utils 0.2.0",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/rocket)",
@ -1050,11 +1164,24 @@ dependencies = [
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "safemem"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
@ -1093,6 +1220,25 @@ dependencies = [
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-fontconfig"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-fontconfig-sys"
version = "4.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-freetype-sys"
version = "4.0.3"
@ -1130,6 +1276,17 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "0.3.6"
@ -1257,15 +1414,6 @@ name = "utf8-ranges"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "uuid-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vec_map"
version = "0.8.1"
@ -1281,6 +1429,15 @@ name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
@ -1295,11 +1452,6 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
@ -1336,12 +1488,15 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33a67fd81e1922dddc335887516f2f5254534e89c9d39fa89bca5d79bd150d34"
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9"
"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13"
"checksum cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b5695f59fd036fe5741bc5a4eb20c78fbe42256e3b08a2af26bbcbe8070bf3"
@ -1350,25 +1505,32 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3"
"checksum cocoa 0.18.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>"
"checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2"
"checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9"
"checksum core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92801c908ea6301ae619ed842a72e01098085fc321b9c2f3f833dad555bba055"
"checksum core-text 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "157ff38a92496dc676ce36d9124554e9ac66f1c1039f952690ac64f71cfa5968"
"checksum core-foundation 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
"checksum core-foundation-sys 0.6.1 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
"checksum core-graphics 0.17.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
"checksum core-text 13.0.0 (git+https://github.com/servo/core-foundation-rs)" = "<none>"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
"checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7918280f33862bc8542212d74f2149b1a87ab402fd15f4ce9a1c56582958d6e"
"checksum dwrote 0.5.0 (git+https://github.com/servo/dwrote-rs)" = "<none>"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
"checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f"
"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
"checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
"checksum font-kit 0.1.0 (git+https://github.com/pcwalton/font-kit)" = "<none>"
"checksum fontsan 0.4.0 (git+https://github.com/servo/fontsan.git)" = "<none>"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
"checksum freetype 0.4.1 (git+https://github.com/servo/rust-freetype)" = "<none>"
"checksum gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16160d212ae91abe9f3324c3fb233929ba322dde63585d15cda3336f8c529ed1"
"checksum gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "798f97101eea8180da363d0e80e07ec7ec6d1809306601c0100c1de5bc8b4f52"
"checksum gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ee916f5f25c5f4b21bd9dcb12a216ae697406940ff9476358c308a8ececada"
@ -1386,9 +1548,9 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
"checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245"
"checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3"
@ -1400,8 +1562,10 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "216bfb2b880554865fa9deaa14671ab9f1368b942e7007cc8c97c083ac8a7f45"
"checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
@ -1412,6 +1576,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9833ab0efe5361b1e2122a0544a5d3359576911a42cb098c2e59be8650807367"
"checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab"
"checksum pear 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=b475140)" = "<none>"
"checksum pear_codegen 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=b475140)" = "<none>"
@ -1435,17 +1600,22 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/rocket)" = "<none>"
"checksum rsvg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2032b49fe075a3b921573286f7debe130aebdac6cb37fb197f9b517a4237024"
"checksum rsvg-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ceca0b663cfddd09062d7e3fe0a729765d1e61bbbbb6a31d5e23d141ff0db38"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920"
"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124"
"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2"
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a"
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8"
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
@ -1464,13 +1634,12 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "383cea1fd3b68c33bbdd25af09bc50e70f4c9f1d9b18e39e514e4acf760ec5d2"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"

View File

@ -1,6 +1,5 @@
[workspace]
members = [
"font-renderer",
"gfx-utils",
"partitioner",
"path-utils",

View File

@ -5,8 +5,8 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[features]
default = []
freetype = ["pathfinder_font_renderer/freetype"]
reftests = ["rsvg", "cairo-rs", "pathfinder_font_renderer/freetype"]
freetype = ["font-kit/loader-freetype-default"]
reftests = ["rsvg", "cairo-rs", "font-kit/loader-freetype-default"]
[dependencies]
app_units = "0.7"
@ -45,8 +45,8 @@ git = "https://github.com/SergioBenitez/rocket"
[dependencies.rocket_contrib]
git = "https://github.com/SergioBenitez/rocket"
[dependencies.pathfinder_font_renderer]
path = "../../font-renderer"
[dependencies.font-kit]
git = "https://github.com/pcwalton/font-kit"
[dependencies.pathfinder_partitioner]
path = "../../partitioner"

View File

@ -15,12 +15,12 @@ extern crate app_units;
extern crate base64;
extern crate env_logger;
extern crate euclid;
extern crate font_kit;
extern crate fontsan;
extern crate image;
extern crate lru_cache;
extern crate lyon_geom;
extern crate lyon_path;
extern crate pathfinder_font_renderer;
extern crate pathfinder_partitioner;
extern crate pathfinder_path_utils;
extern crate rocket;
@ -36,15 +36,17 @@ extern crate cairo;
#[cfg(feature = "reftests")]
extern crate rsvg;
use app_units::Au;
use euclid::{Point2D, Transform2D};
use font_kit::canvas::Format as FontKitFormat;
use font_kit::canvas::{Canvas, RasterizationOptions};
use font_kit::font::Font;
use font_kit::hinting::HintingOptions;
use font_kit::loaders;
use image::{DynamicImage, ImageBuffer, ImageFormat, ImageRgba8};
use lru_cache::LruCache;
use lyon_path::PathEvent;
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
use lyon_path::iterator::PathIter;
use pathfinder_font_renderer::{FontContext, FontInstance, GlyphImage};
use pathfinder_font_renderer::{GlyphKey, SubpixelOffset};
use pathfinder_partitioner::FillRule;
use pathfinder_partitioner::mesh_pack::MeshPack;
use pathfinder_partitioner::partitioner::Partitioner;
@ -58,14 +60,10 @@ use rocket_contrib::json::Json;
use std::fs::File;
use std::io::{self, Cursor, Read};
use std::path::{self, PathBuf};
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::u32;
#[cfg(target_os = "macos")]
use pathfinder_font_renderer::core_graphics;
#[cfg(feature = "reftests")]
use euclid::Size2D;
#[cfg(feature = "reftests")]
@ -79,8 +77,6 @@ const MESH_PACK_CACHE_SIZE: usize = 16;
const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 5.0;
static NEXT_FONT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
lazy_static! {
static ref MESH_PACK_CACHE: Mutex<LruCache<MeshPackCacheKey, PartitionResponder>> = {
Mutex::new(LruCache::new(MESH_PACK_CACHE_SIZE))
@ -267,15 +263,6 @@ struct PartitionSvgPathCommand {
values: Vec<f64>,
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct FontKey(usize);
impl FontKey {
fn new() -> FontKey {
FontKey(NEXT_FONT_KEY.fetch_add(1, Ordering::SeqCst))
}
}
struct PathPartitioningResult {
encoded_data: Arc<Vec<u8>>,
time: Duration,
@ -409,31 +396,6 @@ fn svg_data_from_request(builtin_svg_name: &str) -> Result<Arc<Vec<u8>>, SvgErro
}
}
#[cfg(target_os = "macos")]
fn rasterize_glyph_with_core_graphics(font_key: &FontKey,
font_index: u32,
otf_data: Arc<Vec<u8>>,
font_instance: &FontInstance<FontKey>,
glyph_key: &GlyphKey)
-> Result<GlyphImage, FontError> {
let mut font_context =
try!(core_graphics::FontContext::new().map_err(|_| FontError::FontLoadingFailed));
try!(font_context.add_font_from_memory(font_key, otf_data, font_index)
.map_err(|_| FontError::FontLoadingFailed));
font_context.rasterize_glyph_with_native_rasterizer(&font_instance, &glyph_key, true)
.map_err(|_| FontError::RasterizationFailed)
}
#[cfg(not(target_os = "macos"))]
fn rasterize_glyph_with_core_graphics(_: &FontKey,
_: u32,
_: Arc<Vec<u8>>,
_: &FontInstance<FontKey>,
_: &GlyphKey)
-> Result<GlyphImage, FontError> {
Err(FontError::ReferenceRasterizerUnavailable)
}
#[post("/partition-font", format = "application/json", data = "<request>")]
fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionResponder, FontError> {
// Check the cache.
@ -456,23 +418,10 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
}
// Parse glyph data.
let mut font_context = match FontContext::new() {
Ok(font_context) => font_context,
Err(_) => {
println!("Failed to create a font context!");
return Err(FontError::FontLoadingFailed)
}
};
let font_key = FontKey::new();
let otf_data = try!(otf_data_from_request(&request.face));
if font_context.add_font_from_memory(&font_key, otf_data, request.font_index).is_err() {
return Err(FontError::FontLoadingFailed)
}
let font_instance = FontInstance {
font_key: font_key,
size: Au::from_f64_px(request.point_size),
let font = match Font::from_bytes(otf_data, request.font_index) {
Ok(font) => font,
Err(_) => return Err(FontError::FontLoadingFailed),
};
// Read glyph info.
@ -480,12 +429,12 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon
let mut path_descriptors = vec![];
for (glyph_index, glyph) in request.glyphs.iter().enumerate() {
let glyph_key = GlyphKey::new(glyph.id, SubpixelOffset(0));
// This might fail; if so, just leave it blank.
match font_context.glyph_outline(&font_instance, &glyph_key) {
Ok(glyph_outline) => {
paths.push(Transform2DPathIter::new(glyph_outline.iter(),
// FIXME(pcwalton): Should we add first-class support for transforms to `font-kit`?
let mut path_builder = lyon_path::default::Path::builder();
match font.outline(glyph.id, HintingOptions::None, &mut path_builder) {
Ok(()) => {
paths.push(Transform2DPathIter::new(path_builder.build().into_iter(),
&glyph.transform).collect())
}
Err(_) => paths.push(vec![]),
@ -601,39 +550,60 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
#[post("/render-reference/text", format = "application/json", data = "<request>")]
fn render_reference_text(request: Json<RenderTextReferenceRequest>)
-> Result<ReferenceImage, FontError> {
let font_key = FontKey::new();
let otf_data = try!(otf_data_from_request(&request.face));
let font_instance = FontInstance {
font_key: font_key,
size: Au::from_f64_px(request.point_size),
};
let glyph_key = GlyphKey::new(request.glyph, SubpixelOffset(0));
// Rasterize the glyph using the right rasterizer.
let glyph_image = match request.renderer {
let mut canvas;
match request.renderer {
ReferenceTextRenderer::FreeType => {
let mut font_context =
try!(FontContext::new().map_err(|_| FontError::FontLoadingFailed));
try!(font_context.add_font_from_memory(&font_key, otf_data, request.font_index)
.map_err(|_| FontError::FontLoadingFailed));
try!(font_context.rasterize_glyph_with_native_rasterizer(&font_instance,
&glyph_key,
true)
.map_err(|_| FontError::RasterizationFailed))
let loader = match Font::from_bytes(otf_data, request.font_index) {
Ok(loader) => loader,
Err(_) => return Err(FontError::FontLoadingFailed),
};
let glyph_rect = try!(loader.raster_bounds(request.glyph,
request.point_size as f32,
&Point2D::zero(),
HintingOptions::None,
RasterizationOptions::SubpixelAa)
.map_err(|_| FontError::RasterizationFailed));
let glyph_dimensions = glyph_rect.size.to_u32();
canvas = Canvas::new(&glyph_dimensions, FontKitFormat::Rgba32);
let origin = Point2D::new(-glyph_rect.origin.x, -glyph_rect.origin.y).to_f32();
try!(loader.rasterize_glyph(&mut canvas,
request.glyph,
request.point_size as f32,
&origin,
HintingOptions::None,
RasterizationOptions::SubpixelAa)
.map_err(|_| FontError::RasterizationFailed));
}
ReferenceTextRenderer::CoreGraphics => {
try!(rasterize_glyph_with_core_graphics(&font_key,
request.font_index,
otf_data,
&font_instance,
&glyph_key))
let loader = match loaders::core_text::Font::from_bytes(otf_data, request.font_index) {
Ok(loader) => loader,
Err(_) => return Err(FontError::FontLoadingFailed),
};
let glyph_rect = try!(loader.raster_bounds(request.glyph,
request.point_size as f32,
&Point2D::zero(),
HintingOptions::None,
RasterizationOptions::SubpixelAa)
.map_err(|_| FontError::RasterizationFailed));
let glyph_dimensions = glyph_rect.size.to_u32();
canvas = Canvas::new(&glyph_dimensions, FontKitFormat::Rgba32);
let origin = Point2D::new(-glyph_rect.origin.x, -glyph_rect.origin.y).to_f32();
try!(loader.rasterize_glyph(&mut canvas,
request.glyph,
request.point_size as f32,
&origin,
HintingOptions::None,
RasterizationOptions::SubpixelAa)
.map_err(|_| FontError::RasterizationFailed));
}
};
let dimensions = &glyph_image.dimensions;
let image_buffer = ImageBuffer::from_raw(dimensions.size.width,
dimensions.size.height,
glyph_image.pixels).unwrap();
let image_buffer = ImageBuffer::from_raw(canvas.size.width,
canvas.size.height,
canvas.pixels).unwrap();
let reference_image = ReferenceImage {
image: ImageRgba8(image_buffer),
};

View File

@ -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"

View File

@ -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()
}
}

View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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>,
}

View File

@ -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);
}
}

View File

@ -4,14 +4,12 @@ version = "0.2.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
app_units = "0.7"
clap = "2.27"
freetype = "0.4"
lyon_path = "0.12"
[dependencies.pathfinder_font_renderer]
path = "../../font-renderer"
features = ["freetype"]
[dependencies.font-kit]
git = "https://github.com/pcwalton/font-kit"
features = ["loader-freetype-default"]
[dependencies.pathfinder_partitioner]
path = "../../partitioner"

View File

@ -23,77 +23,38 @@
//! simple storage format for VBOs. To render these paths, you can directly upload these VBOs to
//! the GPU and render them using the shaders provided.
extern crate app_units;
extern crate clap;
extern crate freetype;
extern crate font_kit;
extern crate lyon_path;
extern crate pathfinder_font_renderer;
extern crate pathfinder_partitioner;
extern crate pathfinder_path_utils;
use app_units::Au;
use clap::{App, Arg};
use freetype::freetype::{FT_Init_FreeType, FT_New_Face};
use font_kit::font::Font;
use font_kit::hinting::HintingOptions;
use lyon_path::PathEvent;
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
use pathfinder_font_renderer::{FontContext, FontInstance, GlyphKey, SubpixelOffset};
use lyon_path::default::Path as LyonPath;
use pathfinder_partitioner::FillRule;
use pathfinder_partitioner::mesh_pack::MeshPack;
use pathfinder_partitioner::partitioner::Partitioner;
use std::ffi::CString;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::ptr;
use std::sync::Arc;
const FONT_SIZE: f64 = 72.0;
fn convert_font(font_path: &Path, output_path: &Path) -> Result<(), ()> {
let mut freetype_library = ptr::null_mut();
let glyph_count;
unsafe {
if FT_Init_FreeType(&mut freetype_library) != 0 {
return Err(())
}
// TODO(pcwalton): Allow the user to select a face by index.
let mut freetype_face = ptr::null_mut();
let font_path = match font_path.to_str() {
None => return Err(()),
Some(font_path) => font_path,
};
let font_path = try!(CString::new(font_path).map_err(drop));
if FT_New_Face(freetype_library, font_path.as_ptr(), 0, &mut freetype_face) != 0 {
return Err(())
}
glyph_count = (*freetype_face).num_glyphs as u32;
}
let mut font_data = vec![];
let mut font_file = try!(File::open(font_path).map_err(drop));
try!(font_file.read_to_end(&mut font_data).map_err(drop));
// TODO(pcwalton): Allow the user to select a face by index.
let mut font_context = try!(FontContext::new());
try!(font_context.add_font_from_memory(&(), Arc::new(font_data), 0));
let font_instance = FontInstance {
font_key: (),
size: Au::from_f64_px(FONT_SIZE),
};
let font = try!(Font::from_path(font_path, 0).map_err(drop));
let glyph_count = font.glyph_count();
let mut paths: Vec<(u16, Vec<PathEvent>)> = vec![];
let mut mesh_pack = MeshPack::new();
for glyph_index in 0..glyph_count {
let glyph_key = GlyphKey::new(glyph_index, SubpixelOffset(0));
let path = match font_context.glyph_outline(&font_instance, &glyph_key) {
Ok(path) => path,
Err(_) => continue,
};
let mut path_builder = LyonPath::builder();
if font.outline(glyph_index, HintingOptions::None, &mut path_builder).is_err() {
continue
}
let path = path_builder.build();
let mut partitioner = Partitioner::new();