@@ -46,13 +46,15 @@ family_name(x::FTFont) = lowercase(x.family_name)
46
46
style_name (x:: FTFont ) = lowercase (x. style_name)
47
47
48
48
const REGULAR_STYLES = (" regular" , " normal" , " standard" , " book" , " roman" , " medium" )
49
+ const FONT_EXTENSION_PRIORITY = (" otc" , " otf" , " ttc" , " ttf" , " cff" , " woff2" , " woff" , " pfa" , " pfb" , " pfr" , " fnt" , " pcf" , " bdf" )
49
50
50
51
"""
51
52
score_font(searchparts::Vector{<:AbstractString}, fontpath::String)
52
- score_font(searchparts::Vector{<:AbstractString}, family::String, style::String)
53
+ score_font(searchparts::Vector{<:AbstractString}, family::String, style::String, ext::String )
53
54
54
55
Score a font match using the list user-specified `searchparts`. The font match
55
- can either be a path to a font file (`fontpath`), or a `family` and `style`.
56
+ can either be a path to a font file (`fontpath`), or a `family`, `style`, and
57
+ `ext`.
56
58
57
59
Each part of the search string is searched in the family name first which has to
58
60
match once to include the font in the candidate list. For fonts with a family
@@ -84,7 +86,7 @@ Then this is how this function would match different search strings:
84
86
- "times" => no match
85
87
- "arial" => no match
86
88
"""
87
- function score_font (searchparts:: Vector{<:AbstractString} , family:: String , style:: String ):: Tuple{Int, Int, Int, Int}
89
+ function score_font (searchparts:: Vector{<:AbstractString} , family:: String , style:: String , ext :: String ):: Tuple{Int, Int, Int, Int, Int}
88
90
regularity = minimum ((length (REGULAR_STYLES) + 1 - findfirst (== (regsty), REGULAR_STYLES):: Int
89
91
for regsty in REGULAR_STYLES if occursin (regsty, style)), init= typemax (Int))
90
92
if regularity == typemax (Int)
@@ -96,7 +98,7 @@ function score_font(searchparts::Vector{<:AbstractString}, family::String, style
96
98
97
99
# return early if family name doesn't have a match
98
100
any (occursin (part, family) for part in searchparts) ||
99
- return (0 , 0 , regularity, fontlength_penalty)
101
+ return (0 , 0 , regularity, fontlength_penalty, ext_priority )
100
102
101
103
family_score, style_score = 0 , 0
102
104
for (i, part) in enumerate (Iterators. reverse (searchparts))
@@ -107,18 +109,18 @@ function score_font(searchparts::Vector{<:AbstractString}, family::String, style
107
109
end
108
110
end
109
111
110
- return (family_score + style_score, family_score, regularity, fontlength_penalty)
112
+ return (family_score + style_score, family_score, regularity, fontlength_penalty, ext_priority )
111
113
end
112
114
113
- function score_font (searchparts:: Vector{<:AbstractString} , fontpath:: String ):: Tuple{Int, Int, Int, Int}
115
+ function score_font (searchparts:: Vector{<:AbstractString} , fontpath:: String ):: Tuple{Int, Int, Int, Int, Int }
114
116
if (finfo = font_info (fontpath)) |> ! isnothing
115
- score_font (searchparts, finfo. family, finfo. style)
117
+ score_font (searchparts, finfo. family, finfo. style, finfo . ext )
116
118
else
117
- (0 , 0 , 0 , typemin (Int))
119
+ (0 , 0 , 0 , typemin (Int), length (FONT_EXTENSION_PRIORITY) + 1 )
118
120
end
119
121
end
120
122
121
- const FONTINFO_CACHE = Dict{String, Union{NamedTuple{(:family , :style ), Tuple{String, String}}, Nothing}}()
123
+ const FONTINFO_CACHE = Dict{String, Union{NamedTuple{(:family , :style , :ext ), Tuple{String, String, String}}, Nothing}}()
122
124
123
125
function font_info (fontpath:: String )
124
126
if isfile (fontpath)
@@ -128,7 +130,7 @@ function font_info(fontpath::String)
128
130
family = family_name (font)
129
131
style = style_name (font)
130
132
finalize (font)
131
- (; family= family, style= style)
133
+ (; family= family, style= style, ext = last ( split (fontpath, ' . ' )) )
132
134
end
133
135
end
134
136
end
@@ -174,14 +176,15 @@ function findfont_nocache(searchstring::String, fontfolders::Vector{<:AbstractSt
174
176
# \W splits at all groups of non-word characters (like space, -, ., etc)
175
177
searchparts = unique (split (lowercase (searchstring), r" \W +" , keepempty= false ))
176
178
max_score1 = sum (length, searchparts) + sum (1 : length (searchparts))
177
- best_1i, best_file, best_score = 0 , nothing , (0 , 0 , false , typemin (Int))
179
+ best_1i, best_file, best_score = 0 , nothing , (0 , 0 , 0 , typemin (Int), 0 )
178
180
for (i, fontfile) in enumerate (fontfiles_guess_sorted (searchparts, fontfolders))
179
- # we can compare all four tuple elements of the score at once
181
+ # we can compare all five tuple elements of the score at once
180
182
# in order of importance:
181
183
# 1. number of family and style match characters (with priority factor)
182
184
# 2. number of family match characters (with priority factor)
183
185
# 3. is font a "regular" style variant?
184
186
# 4. the negative length of the font name, the shorter the better
187
+ # 5. the font file extension priority
185
188
score = score_font (searchparts, fontfile)
186
189
if first (score) > 0 && score >= best_score
187
190
best_1i = i
0 commit comments