@@ -35,6 +35,16 @@ struct FontExtent{T}
35
35
scale:: Vec{2, T}
36
36
end
37
37
38
+ hadvance (ext:: FontExtent ) = ext. advance[1 ]
39
+ inkwidth (ext:: FontExtent ) = ext. scale[1 ]
40
+ inkheight (ext:: FontExtent ) = ext. scale[2 ]
41
+ hbearing_ori_to_left (ext:: FontExtent ) = ext. horizontal_bearing[1 ]
42
+ hbearing_ori_to_top (ext:: FontExtent ) = ext. horizontal_bearing[2 ]
43
+ leftinkbound (ext:: FontExtent ) = hbearing_ori_to_left (ext)
44
+ rightinkbound (ext:: FontExtent ) = leftinkbound (ext) + inkwidth (ext)
45
+ bottominkbound (ext:: FontExtent ) = hbearing_ori_to_top (ext) - inkheight (ext)
46
+ topinkbound (ext:: FontExtent ) = hbearing_ori_to_top (ext)
47
+
38
48
BroadcastStyle (:: Type{<: FontExtent} ) = Style {FontExtent} ()
39
49
BroadcastStyle (:: Style{FontExtent} , x) = Style {FontExtent} ()
40
50
BroadcastStyle (x, :: Style{FontExtent} ) = Style {FontExtent} ()
@@ -110,20 +120,18 @@ end
110
120
111
121
mutable struct FTFont
112
122
ft_ptr:: FreeType.FT_Face
113
- current_pixelsize:: Base.RefValue{Int}
114
123
use_cache:: Bool
115
- cache :: Dict{Tuple{Int, Char} , FontExtent{Float32}}
116
- function FTFont (ft_ptr:: FreeType.FT_Face , pixel_size :: Int = 64 , use_cache:: Bool = true )
117
- cache = Dict {Tuple{Int, Char}, FontExtent{Float32}} ()
118
- face = new (ft_ptr, Ref (pixel_size), use_cache, cache )
124
+ extent_cache :: Dict{Char, FontExtent{Float32}}
125
+ function FTFont (ft_ptr:: FreeType.FT_Face , use_cache:: Bool = true )
126
+ extent_cache = Dict {Tuple{Int, Char}, FontExtent{Float32}} ()
127
+ face = new (ft_ptr, use_cache, extent_cache )
119
128
finalizer (safe_free, face)
120
- FT_Set_Pixel_Sizes (face, pixel_size, 0 );
121
129
return face
122
130
end
123
131
end
124
132
125
133
use_cache (face:: FTFont ) = getfield (face, :use_cache )
126
- get_cache (face:: FTFont ) = getfield (face, :cache )
134
+ get_cache (face:: FTFont ) = getfield (face, :extent_cache )
127
135
128
136
function FTFont (path:: String )
129
137
return FTFont (newface (path))
159
167
# Allow broadcasting over fonts
160
168
Base. Broadcast. broadcastable (ft:: FTFont ) = Ref (ft)
161
169
162
- get_pixelsize (face:: FTFont ) = getfield (face, :current_pixelsize )[]
163
-
164
170
function set_pixelsize (face:: FTFont , size:: Integer )
165
- get_pixelsize (face) == size && return size
166
171
err = FT_Set_Pixel_Sizes (face, size, size)
167
172
check_error (err, " Couldn't set pixelsize" )
168
- getfield (face, :current_pixelsize )[] = size
169
173
return size
170
174
end
171
175
@@ -181,14 +185,9 @@ function kerning(c1::Char, c2::Char, face::FTFont)
181
185
return Vec2f0 (kerning2d[]. x / divisor, kerning2d[]. y / divisor)
182
186
end
183
187
184
- function loadchar (face:: FTFont , c:: Char )
185
- err = FT_Load_Char (face, c, FT_LOAD_RENDER)
186
- check_error (err, " Could not load char to render." )
187
- end
188
-
189
188
function get_extent (face:: FTFont , char:: Char )
190
189
if use_cache (face)
191
- get! (get_cache (face), ( get_pixelsize (face), char) ) do
190
+ get! (get_cache (face), char) do
192
191
return internal_get_extent (face, char)
193
192
end
194
193
else
@@ -197,9 +196,20 @@ function get_extent(face::FTFont, char::Char)
197
196
end
198
197
199
198
function internal_get_extent (face:: FTFont , char:: Char )
200
- err = FT_Load_Char (face, char, FT_LOAD_DEFAULT)
201
- check_error (err, " Could not load char to get extend." )
202
- metrics = face. glyph. metrics
203
- # 64 since metrics are in 1/64 units (units to 26.6 fractional pixels)
204
- return FontExtent (metrics, Float32 (64 ))
205
- end
199
+ #=
200
+ Load chars without scaling. This leaves all glyph metrics that can be
201
+ retrieved in font units, which can be normalized by dividing with the
202
+ font's units_per_EM. This is more robust than relying on extents
203
+ that are only valid with a specific pixelsize, because a font's
204
+ pixelsize can be silently changed by third parties, such as Cairo.
205
+ If that happens, all glyph metrics are incorrect. We avoid this by using the normalized space.
206
+ =#
207
+ err = FT_Load_Char (face, char, FT_LOAD_NO_SCALE)
208
+ check_error (err, " Could not load char to get extent." )
209
+ # This gives us the font metrics in normalized units (0, 1), with negative
210
+ # numbers interpreted as an offset
211
+ return FontExtent (face. glyph. metrics, Float32 (face. units_per_EM))
212
+ end
213
+
214
+ descender (font) = font. descender / font. units_per_EM
215
+ ascender (font) = font. ascender / font. units_per_EM
0 commit comments