-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathFontconfig.jl
167 lines (130 loc) · 5.28 KB
/
Fontconfig.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
module Fontconfig
depsfile = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
if isfile(depsfile)
include(depsfile)
else
error("Fontconfig.jl not properly installed. Please run `Pkg.build(\"Fontconfig\")` " *
"and restart Julia.")
end
import Base.Sys
using Printf
export format, match, list
function __init__()
ENV["FONTCONFIG_FILE"] = joinpath(dirname(jl_libfontconfig), "..", "etc", "fonts", "fonts.conf")
ccall((:FcInit, jl_libfontconfig), UInt8, ())
# By default fontconfig on OSX does not include user fonts.
@static if Sys.isapple()
ccall((:FcConfigAppFontAddDir, jl_libfontconfig),
UInt8, (Ptr{Nothing}, Ptr{UInt8}),
C_NULL, b"~/Library/Fonts")
end
end
const FcMatchPattern = UInt32(0)
const FcMatchFont = UInt32(1)
const FcMatchScan = UInt32(2)
const string_attrs = Set([:family, :style, :foundry, :file, :lang,
:fullname, :familylang, :stylelang, :fullnamelang,
:compatibility, :fontformat, :fontfeatures, :namelang,
:prgname, :hash, :postscriptname])
const double_attrs = Set([:size, :aspect, :pixelsize, :scale, :dpi])
const integer_attrs = Set([:slant, :weight, :spacing, :hintstyle, :width, :index,
:rgba, :fontversion, :lcdfilter])
const bool_attrs = Set([:antialias, :histing, :verticallayout, :autohint, :outline,
:scalable, :minspace, :embolden, :embeddedbitmap,
:decorative])
mutable struct Pattern
ptr::Ptr{Nothing}
function Pattern(; args...)
ptr = ccall((:FcPatternCreate, jl_libfontconfig), Ptr{Nothing}, ())
for (attr, value) in args
if attr in string_attrs
ccall((:FcPatternAddString, jl_libfontconfig), Cint,
(Ptr{Nothing}, Ptr{UInt8}, Ptr{UInt8}),
ptr, string(attr), value)
elseif attr in double_attrs
ccall((:FcPatternAddDouble, jl_libfontconfig), Cint,
(Ptr{Nothing}, Ptr{UInt8}, Cdouble),
ptr, string(attr), value)
elseif attr in integer_attrs
ccall((:FcPatternAddInteger, jl_libfontconfig), Cint,
(Ptr{Nothing}, Ptr{UInt8}, Cint),
ptr, string(attr), value)
elseif attr in bool_attrs
ccall((:FcPatternAddBool, jl_libfontconfig), Cint,
(Ptr{Nothing}, Ptr{UInt8}, Cint),
ptr, string(attr), value)
end
end
pat = new(ptr)
finalizer(pat -> ccall((:FcPatternDestroy, jl_libfontconfig), Nothing,
(Ptr{Nothing},), pat.ptr), pat)
return pat
end
function Pattern(ptr::Ptr{Nothing})
return new(ptr)
end
function Pattern(name::AbstractString)
ptr = ccall((:FcNameParse, jl_libfontconfig), Ptr{Nothing}, (Ptr{UInt8},), name)
pat = new(ptr)
finalizer(pat -> ccall((:FcPatternDestroy, jl_libfontconfig), Nothing,
(Ptr{Nothing},), pat.ptr), pat)
return pat
end
end
function Base.show(io::IO, pat::Pattern)
desc = ccall((:FcNameUnparse, jl_libfontconfig), Ptr{UInt8},
(Ptr{Nothing},), pat.ptr)
@printf(io, "Fontconfig.Pattern(\"%s\")", unsafe_string(desc))
Libc.free(desc)
end
function Base.match(pat::Pattern, default_substitute::Bool=true)
ccall((:FcConfigSubstitute, jl_libfontconfig),
UInt8, (Ptr{Nothing}, Ptr{Nothing}, Int32),
C_NULL, pat.ptr, FcMatchPattern)
if default_substitute
ccall((:FcDefaultSubstitute, jl_libfontconfig),
Nothing, (Ptr{Nothing},), pat.ptr)
end
result = Int32[0]
mat = ccall((:FcFontMatch, jl_libfontconfig),
Ptr{Nothing}, (Ptr{Nothing}, Ptr{Nothing}, Ptr{Int32}),
C_NULL, pat.ptr, result)
if result[1] != 0
error(string("Fontconfig was unable to match font ", pat))
end
return Pattern(mat)
end
function format(pat::Pattern, fmt::AbstractString="%{=fclist}")
desc = ccall((:FcPatternFormat, jl_libfontconfig), Ptr{UInt8},
(Ptr{Nothing}, Ptr{UInt8}), pat.ptr, fmt)
if desc == C_NULL
error("Invalid fontconfig format.")
end
descstr = unsafe_string(desc)
Libc.free(desc)
return descstr
end
struct FcFontSet
nfont::Cint
sfont::Cint
fonts::Ptr{Ptr{Nothing}}
end
function list(pat::Pattern=Pattern())
os = ccall((:FcObjectSetCreate, jl_libfontconfig), Ptr{Nothing}, ())
ccall((:FcObjectSetAdd, jl_libfontconfig), Cint, (Ptr{Nothing}, Ptr{UInt8}),
os, "family")
ccall((:FcObjectSetAdd, jl_libfontconfig), Cint, (Ptr{Nothing}, Ptr{UInt8}),
os, "style")
ccall((:FcObjectSetAdd, jl_libfontconfig), Cint, (Ptr{Nothing}, Ptr{UInt8}),
os, "file")
fs_ptr = ccall((:FcFontList, jl_libfontconfig), Ptr{FcFontSet},
(Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), C_NULL, pat.ptr, os)
fs = unsafe_load(fs_ptr)
patterns = Pattern[]
for i in 1:fs.nfont
push!(patterns, Pattern(unsafe_load(fs.fonts, i)))
end
ccall((:FcObjectSetDestroy, jl_libfontconfig), Nothing, (Ptr{Nothing},), os)
return patterns
end
end # module