blitz-pdf 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -11
- package/THIRD_PARTY_NOTICES.md +19 -1
- package/dist/api.d.ts +2 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +31 -6
- package/dist/api.js.map +1 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +6 -2
- package/dist/node.js.map +1 -1
- package/dist/types.d.ts +16 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/worker-host.d.ts +10 -5
- package/dist/worker-host.d.ts.map +1 -1
- package/dist/worker-host.js +149 -28
- package/dist/worker-host.js.map +1 -1
- package/dist/worker-protocol.d.ts +5 -0
- package/dist/worker-protocol.d.ts.map +1 -1
- package/dist/worker-runtime.d.ts +1 -1
- package/dist/worker-runtime.d.ts.map +1 -1
- package/dist/worker-runtime.js +22 -6
- package/dist/worker-runtime.js.map +1 -1
- package/licenses/Noto-OFL.txt +94 -0
- package/licenses/NotoCJK-OFL.txt +92 -0
- package/licenses/NotoEmoji-OFL.txt +93 -0
- package/licenses/RUST_DEPENDENCIES.txt +34 -40
- package/licenses/Unifont-OFL.txt +90 -0
- package/licenses/font-sources.json +106 -0
- package/package.json +1 -1
- package/src/api.ts +32 -7
- package/src/browser.ts +2 -1
- package/src/node.ts +7 -2
- package/src/types.ts +17 -1
- package/src/worker-host.ts +148 -29
- package/src/worker-protocol.ts +5 -5
- package/src/worker-runtime.ts +20 -6
- package/vendor/README.md +38 -5
- package/vendor/blitz-dom/Cargo.toml +6 -6
- package/vendor/blitz-dom/src/accessibility.rs +175 -2
- package/vendor/blitz-dom/src/config.rs +8 -10
- package/vendor/blitz-dom/src/document.rs +66 -3
- package/vendor/blitz-dom/src/events/keyboard.rs +2 -6
- package/vendor/blitz-dom/src/layout/construct.rs +5 -300
- package/vendor/blitz-dom/src/layout/inline/build.rs +309 -0
- package/vendor/blitz-dom/src/layout/{inline.rs → inline/layout.rs} +1 -1
- package/vendor/blitz-dom/src/layout/inline/mod.rs +4 -0
- package/vendor/blitz-dom/src/layout/mod.rs +3 -1
- package/vendor/blitz-dom/src/layout/replaced.rs +13 -4
- package/vendor/blitz-dom/src/mutator.rs +47 -0
- package/vendor/blitz-dom/src/node/element.rs +17 -0
- package/vendor/blitz-dom/src/node/mod.rs +1 -0
- package/vendor/blitz-dom/src/node/node.rs +46 -5
- package/vendor/blitz-dom/src/node/text.rs +11 -11
- package/vendor/blitz-dom/src/resolve.rs +2 -2
- package/vendor/blitz-dom/src/stylo.rs +30 -22
- package/vendor/blitz-dom/src/util.rs +1 -1
- package/vendor/blitz-paint/Cargo.toml +4 -4
- package/vendor/fontique/Cargo.toml +194 -0
- package/vendor/fontique/LICENSE-APACHE +201 -0
- package/vendor/fontique/LICENSE-MIT +25 -0
- package/vendor/fontique/README.md +54 -0
- package/vendor/fontique/examples/generic_families.rs +37 -0
- package/vendor/fontique/src/attributes.rs +42 -0
- package/vendor/fontique/src/backend/android.rs +218 -0
- package/vendor/fontique/src/backend/coretext.rs +206 -0
- package/vendor/fontique/src/backend/dwrite.rs +395 -0
- package/vendor/fontique/src/backend/fontconfig.rs +844 -0
- package/vendor/fontique/src/backend/mod.rs +75 -0
- package/vendor/fontique/src/charmap.rs +127 -0
- package/vendor/fontique/src/collection/mod.rs +1016 -0
- package/vendor/fontique/src/collection/query.rs +392 -0
- package/vendor/fontique/src/fallback.rs +293 -0
- package/vendor/fontique/src/family.rs +111 -0
- package/vendor/fontique/src/family_name.rs +153 -0
- package/vendor/fontique/src/font.rs +562 -0
- package/vendor/fontique/src/generic.rs +36 -0
- package/vendor/fontique/src/impl_fontconfig.rs +159 -0
- package/vendor/fontique/src/lib.rs +87 -0
- package/vendor/fontique/src/matching.rs +483 -0
- package/vendor/fontique/src/scan.rs +312 -0
- package/vendor/fontique/src/script.rs +271 -0
- package/vendor/fontique/src/source.rs +108 -0
- package/vendor/fontique/src/source_cache.rs +254 -0
- package/wasm/blitz_pdf_bg.wasm +0 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
// Copyright 2024 the Parley Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
3
|
+
|
|
4
|
+
//! Implementation of the CSS font matching algorithm.
|
|
5
|
+
|
|
6
|
+
use super::font::FontInfo;
|
|
7
|
+
use crate::{FontStyle, FontWeight, FontWidth};
|
|
8
|
+
use smallvec::SmallVec;
|
|
9
|
+
|
|
10
|
+
const DEFAULT_OBLIQUE_ANGLE: f32 = 14.0;
|
|
11
|
+
|
|
12
|
+
pub(crate) fn match_fonts(
|
|
13
|
+
set: &[FontInfo],
|
|
14
|
+
width: FontWidth,
|
|
15
|
+
style: FontStyle,
|
|
16
|
+
weight: FontWeight,
|
|
17
|
+
synthesize_style: bool,
|
|
18
|
+
) -> impl Iterator<Item = usize> + '_ {
|
|
19
|
+
let best = match_font(set, width, style, weight, synthesize_style).map(|index| {
|
|
20
|
+
let font = &set[index];
|
|
21
|
+
(font.width(), font.style(), font.weight())
|
|
22
|
+
});
|
|
23
|
+
set.iter().enumerate().filter_map(move |(index, font)| {
|
|
24
|
+
let (best_width, best_style, best_weight) = best?;
|
|
25
|
+
// We need to return each font with the best attributes, as there might be multiple subsets.
|
|
26
|
+
(font.width() == best_width && font.style() == best_style && font.weight() == best_weight)
|
|
27
|
+
.then_some(index)
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn match_font(
|
|
32
|
+
set: &[FontInfo],
|
|
33
|
+
width: FontWidth,
|
|
34
|
+
style: FontStyle,
|
|
35
|
+
weight: FontWeight,
|
|
36
|
+
synthesize_style: bool,
|
|
37
|
+
) -> Option<usize> {
|
|
38
|
+
const OBLIQUE_THRESHOLD: f32 = DEFAULT_OBLIQUE_ANGLE;
|
|
39
|
+
match set.len() {
|
|
40
|
+
0 => return None,
|
|
41
|
+
1 => return Some(0),
|
|
42
|
+
_ => {}
|
|
43
|
+
}
|
|
44
|
+
#[derive(Copy, Clone)]
|
|
45
|
+
struct Candidate {
|
|
46
|
+
index: usize,
|
|
47
|
+
width: i32,
|
|
48
|
+
style: FontStyle,
|
|
49
|
+
weight: f32,
|
|
50
|
+
has_slnt: bool,
|
|
51
|
+
}
|
|
52
|
+
let mut set: SmallVec<[Candidate; 16]> = set
|
|
53
|
+
.iter()
|
|
54
|
+
.enumerate()
|
|
55
|
+
.map(|(i, font)| Candidate {
|
|
56
|
+
index: i,
|
|
57
|
+
width: (font.width().ratio() * 100.0) as i32,
|
|
58
|
+
style: font.style(),
|
|
59
|
+
weight: font.weight().value(),
|
|
60
|
+
has_slnt: font.has_slant_axis(),
|
|
61
|
+
})
|
|
62
|
+
.collect();
|
|
63
|
+
let width = (width.ratio() * 100.0) as i32;
|
|
64
|
+
let weight = weight.value();
|
|
65
|
+
// font-width is tried first:
|
|
66
|
+
let mut use_width = set[0].width;
|
|
67
|
+
if !set.iter().any(|f| f.width == width) {
|
|
68
|
+
// If the desired width value is less than or equal to 100%...
|
|
69
|
+
if width <= 100 {
|
|
70
|
+
// width values below the desired width value are checked in
|
|
71
|
+
// descending order...
|
|
72
|
+
if let Some(found) = set
|
|
73
|
+
.iter()
|
|
74
|
+
.filter(|f| f.width < width)
|
|
75
|
+
.max_by_key(|f| f.width)
|
|
76
|
+
{
|
|
77
|
+
use_width = found.width;
|
|
78
|
+
}
|
|
79
|
+
// followed by width values above the desired width value in
|
|
80
|
+
// ascending order until a match is found.
|
|
81
|
+
else if let Some(found) = set
|
|
82
|
+
.iter()
|
|
83
|
+
.filter(|f| f.width > width)
|
|
84
|
+
.min_by_key(|f| f.width)
|
|
85
|
+
{
|
|
86
|
+
use_width = found.width;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Otherwise, ...
|
|
90
|
+
else {
|
|
91
|
+
// width values above the desired width value are checked in
|
|
92
|
+
// ascending order...
|
|
93
|
+
if let Some(found) = set
|
|
94
|
+
.iter()
|
|
95
|
+
.filter(|f| f.width > width)
|
|
96
|
+
.min_by_key(|f| f.width)
|
|
97
|
+
{
|
|
98
|
+
use_width = found.width;
|
|
99
|
+
}
|
|
100
|
+
// followed by width values below the desired width value in
|
|
101
|
+
// descending order until a match is found.
|
|
102
|
+
else if let Some(found) = set
|
|
103
|
+
.iter()
|
|
104
|
+
.filter(|f| f.width < width)
|
|
105
|
+
.max_by_key(|f| f.width)
|
|
106
|
+
{
|
|
107
|
+
use_width = found.width;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
use_width = width;
|
|
112
|
+
}
|
|
113
|
+
set.retain(|f| f.width == use_width);
|
|
114
|
+
use core::cmp::Ordering::*;
|
|
115
|
+
let oblique_fonts = set.iter().filter_map(|f| oblique_style(f.style));
|
|
116
|
+
// font-style is tried next:
|
|
117
|
+
// NOTE: this code uses an oblique threshold of 14deg rather than
|
|
118
|
+
// the current value of 20deg in the spec.
|
|
119
|
+
// See: https://github.com/w3c/csswg-drafts/issues/2295
|
|
120
|
+
let mut use_style = style;
|
|
121
|
+
let mut _use_slnt = false;
|
|
122
|
+
if !set.iter().any(|f| f.style == use_style) {
|
|
123
|
+
// If the value of font-style is italic:
|
|
124
|
+
if style == FontStyle::Italic {
|
|
125
|
+
// oblique values greater than or equal to 14deg are checked in
|
|
126
|
+
// ascending order
|
|
127
|
+
if let Some(found) = oblique_fonts
|
|
128
|
+
.clone()
|
|
129
|
+
.filter(|(_, a)| *a >= OBLIQUE_THRESHOLD)
|
|
130
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
131
|
+
{
|
|
132
|
+
use_style = found.0;
|
|
133
|
+
}
|
|
134
|
+
// followed by positive oblique values below 14deg in descending order
|
|
135
|
+
else if let Some(found) = oblique_fonts
|
|
136
|
+
.clone()
|
|
137
|
+
.filter(|(_, a)| *a > 0. && *a < OBLIQUE_THRESHOLD)
|
|
138
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
139
|
+
{
|
|
140
|
+
use_style = found.0;
|
|
141
|
+
}
|
|
142
|
+
// If no match is found, oblique values less than or equal to 0deg
|
|
143
|
+
// are checked in descending order until a match is found.
|
|
144
|
+
else if let Some(found) = oblique_fonts
|
|
145
|
+
.clone()
|
|
146
|
+
.filter(|(_, a)| *a < 0.)
|
|
147
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
148
|
+
{
|
|
149
|
+
use_style = found.0;
|
|
150
|
+
} else {
|
|
151
|
+
use_style = set[0].style;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// If the value of font-style is oblique...
|
|
155
|
+
else if let Some(angle) = oblique_angle(style) {
|
|
156
|
+
// and the requested angle is greater than or equal to 14deg
|
|
157
|
+
if angle >= OBLIQUE_THRESHOLD {
|
|
158
|
+
// oblique values greater than or equal to angle are checked in
|
|
159
|
+
// ascending order
|
|
160
|
+
if let Some(found) = oblique_fonts
|
|
161
|
+
.clone()
|
|
162
|
+
.filter(|(_, a)| *a >= angle)
|
|
163
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
164
|
+
{
|
|
165
|
+
use_style = found.0;
|
|
166
|
+
}
|
|
167
|
+
// followed by positive oblique values below angle in descending order
|
|
168
|
+
else if let Some(found) = oblique_fonts
|
|
169
|
+
.clone()
|
|
170
|
+
.filter(|(_, a)| *a > 0. && *a < angle)
|
|
171
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
172
|
+
{
|
|
173
|
+
use_style = found.0;
|
|
174
|
+
} else {
|
|
175
|
+
// If font-synthesis-style has the value auto, then for variable
|
|
176
|
+
// fonts with a slnt axis a match is created by setting the slnt
|
|
177
|
+
// value with the specified oblique value; otherwise, a fallback
|
|
178
|
+
// match is produced by geometric shearing to the specified
|
|
179
|
+
// oblique value.
|
|
180
|
+
if synthesize_style {
|
|
181
|
+
if set.iter().any(|f| f.has_slnt) {
|
|
182
|
+
_use_slnt = true;
|
|
183
|
+
} else {
|
|
184
|
+
use_style = if set.iter().any(|f| f.style == FontStyle::Normal) {
|
|
185
|
+
FontStyle::Normal
|
|
186
|
+
} else {
|
|
187
|
+
set[0].style
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
// Choose an italic style
|
|
192
|
+
if set.iter().any(|f| f.style == FontStyle::Italic) {
|
|
193
|
+
use_style = FontStyle::Italic;
|
|
194
|
+
}
|
|
195
|
+
// oblique values less than or equal to 0deg are checked in descending order
|
|
196
|
+
else if let Some(found) = oblique_fonts
|
|
197
|
+
.clone()
|
|
198
|
+
.filter(|(_, a)| *a <= 0.)
|
|
199
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
200
|
+
{
|
|
201
|
+
use_style = found.0;
|
|
202
|
+
} else {
|
|
203
|
+
use_style = set[0].style;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// if the requested angle is greater than or equal to 0deg
|
|
209
|
+
// and less than 14deg
|
|
210
|
+
else if angle >= 0. {
|
|
211
|
+
// positive oblique values below angle in descending order
|
|
212
|
+
if let Some(found) = oblique_fonts
|
|
213
|
+
.clone()
|
|
214
|
+
.filter(|(_, a)| *a > 0. && *a < angle)
|
|
215
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
216
|
+
{
|
|
217
|
+
use_style = found.0;
|
|
218
|
+
}
|
|
219
|
+
// followed by oblique values greater than or equal to angle in
|
|
220
|
+
// ascending order
|
|
221
|
+
else if let Some(found) = oblique_fonts
|
|
222
|
+
.clone()
|
|
223
|
+
.filter(|(_, a)| *a >= angle)
|
|
224
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
225
|
+
{
|
|
226
|
+
use_style = found.0;
|
|
227
|
+
} else {
|
|
228
|
+
// If font-synthesis-style has the value auto, then for variable
|
|
229
|
+
// fonts with a slnt axis a match is created by setting the slnt
|
|
230
|
+
// value with the specified oblique value; otherwise, a fallback
|
|
231
|
+
// match is produced by geometric shearing to the specified
|
|
232
|
+
// oblique value.
|
|
233
|
+
if synthesize_style {
|
|
234
|
+
if set.iter().any(|f| f.has_slnt) {
|
|
235
|
+
_use_slnt = true;
|
|
236
|
+
} else {
|
|
237
|
+
use_style = if set.iter().any(|f| f.style == FontStyle::Normal) {
|
|
238
|
+
FontStyle::Normal
|
|
239
|
+
} else {
|
|
240
|
+
set[0].style
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
// Choose an italic style
|
|
245
|
+
if set.iter().any(|f| f.style == FontStyle::Italic) {
|
|
246
|
+
use_style = FontStyle::Italic;
|
|
247
|
+
}
|
|
248
|
+
// oblique values less than or equal to 0deg are checked in descending order
|
|
249
|
+
else if let Some(found) = oblique_fonts
|
|
250
|
+
.clone()
|
|
251
|
+
.filter(|(_, a)| *a <= 0.)
|
|
252
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
253
|
+
{
|
|
254
|
+
use_style = found.0;
|
|
255
|
+
} else {
|
|
256
|
+
use_style = set[0].style;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// -14deg < angle < 0deg
|
|
262
|
+
else if angle > -OBLIQUE_THRESHOLD {
|
|
263
|
+
// negative oblique values above angle in ascending order
|
|
264
|
+
if let Some(found) = oblique_fonts
|
|
265
|
+
.clone()
|
|
266
|
+
.filter(|(_, a)| *a < 0. && *a > angle)
|
|
267
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
268
|
+
{
|
|
269
|
+
use_style = found.0;
|
|
270
|
+
}
|
|
271
|
+
// followed by oblique values less than or equal to angle in
|
|
272
|
+
// descending order
|
|
273
|
+
else if let Some(found) = oblique_fonts
|
|
274
|
+
.clone()
|
|
275
|
+
.filter(|(_, a)| *a <= angle)
|
|
276
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
277
|
+
{
|
|
278
|
+
use_style = found.0;
|
|
279
|
+
} else {
|
|
280
|
+
// If font-synthesis-style has the value auto, then for variable
|
|
281
|
+
// fonts with a slnt axis a match is created by setting the slnt
|
|
282
|
+
// value with the specified oblique value; otherwise, a fallback
|
|
283
|
+
// match is produced by geometric shearing to the specified
|
|
284
|
+
// oblique value.
|
|
285
|
+
if synthesize_style {
|
|
286
|
+
if set.iter().any(|f| f.has_slnt) {
|
|
287
|
+
_use_slnt = true;
|
|
288
|
+
} else {
|
|
289
|
+
use_style = if set.iter().any(|f| f.style == FontStyle::Normal) {
|
|
290
|
+
FontStyle::Normal
|
|
291
|
+
} else {
|
|
292
|
+
set[0].style
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
// Choose an italic style
|
|
297
|
+
if set.iter().any(|f| f.style == FontStyle::Italic) {
|
|
298
|
+
use_style = FontStyle::Italic;
|
|
299
|
+
}
|
|
300
|
+
// oblique values greater than or equal to 0deg are checked in ascending order
|
|
301
|
+
else if let Some(found) = oblique_fonts
|
|
302
|
+
.clone()
|
|
303
|
+
.filter(|(_, a)| *a >= 0.)
|
|
304
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
305
|
+
{
|
|
306
|
+
use_style = found.0;
|
|
307
|
+
} else {
|
|
308
|
+
use_style = set[0].style;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// angle < -14 deg
|
|
314
|
+
else {
|
|
315
|
+
// oblique values less than or equal to angle are checked in
|
|
316
|
+
// descending order
|
|
317
|
+
if let Some(found) = oblique_fonts
|
|
318
|
+
.clone()
|
|
319
|
+
.filter(|(_, a)| *a <= angle)
|
|
320
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
321
|
+
{
|
|
322
|
+
use_style = found.0;
|
|
323
|
+
}
|
|
324
|
+
// followed by negative oblique values above angle in ascending order
|
|
325
|
+
else if let Some(found) = oblique_fonts
|
|
326
|
+
.clone()
|
|
327
|
+
.filter(|(_, a)| *a < 0. && *a > angle)
|
|
328
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
329
|
+
{
|
|
330
|
+
use_style = found.0;
|
|
331
|
+
} else {
|
|
332
|
+
// If font-synthesis-style has the value auto, then for variable
|
|
333
|
+
// fonts with a slnt axis a match is created by setting the slnt
|
|
334
|
+
// value with the specified oblique value; otherwise, a fallback
|
|
335
|
+
// match is produced by geometric shearing to the specified
|
|
336
|
+
// oblique value.
|
|
337
|
+
if synthesize_style {
|
|
338
|
+
if set.iter().any(|f| f.has_slnt) {
|
|
339
|
+
_use_slnt = true;
|
|
340
|
+
} else {
|
|
341
|
+
use_style = if set.iter().any(|f| f.style == FontStyle::Normal) {
|
|
342
|
+
FontStyle::Normal
|
|
343
|
+
} else {
|
|
344
|
+
set[0].style
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
// Choose an italic style
|
|
349
|
+
if set.iter().any(|f| f.style == FontStyle::Italic) {
|
|
350
|
+
use_style = FontStyle::Italic;
|
|
351
|
+
}
|
|
352
|
+
// oblique values greater than or equal to 0deg are checked in ascending order
|
|
353
|
+
else if let Some(found) = oblique_fonts
|
|
354
|
+
.clone()
|
|
355
|
+
.filter(|(_, a)| *a >= 0.)
|
|
356
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
357
|
+
{
|
|
358
|
+
use_style = found.0;
|
|
359
|
+
} else {
|
|
360
|
+
use_style = set[0].style;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// If the value of font-style is normal...
|
|
367
|
+
else {
|
|
368
|
+
// oblique values greater than or equal to 0deg are checked in
|
|
369
|
+
// ascending order
|
|
370
|
+
if let Some(found) = oblique_fonts
|
|
371
|
+
.clone()
|
|
372
|
+
.filter(|(_, a)| *a >= 0.)
|
|
373
|
+
.min_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
374
|
+
{
|
|
375
|
+
use_style = found.0;
|
|
376
|
+
}
|
|
377
|
+
// followed by italic fonts
|
|
378
|
+
else if let Some(found) = set.iter().find(|f| f.style == FontStyle::Italic) {
|
|
379
|
+
use_style = found.style;
|
|
380
|
+
}
|
|
381
|
+
// followed by oblique values less than 0deg in descending order
|
|
382
|
+
else if let Some(found) = oblique_fonts
|
|
383
|
+
.clone()
|
|
384
|
+
.filter(|(_, a)| *a < 0.)
|
|
385
|
+
.max_by(|x, y| x.1.partial_cmp(&y.1).unwrap_or(Less))
|
|
386
|
+
{
|
|
387
|
+
use_style = found.0;
|
|
388
|
+
} else {
|
|
389
|
+
use_style = set[0].style;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
set.retain(|f| f.style == use_style);
|
|
394
|
+
// font-weight is matched next:
|
|
395
|
+
if let Some(f) = set.iter().find(|f| f.weight == weight) {
|
|
396
|
+
return Some(f.index);
|
|
397
|
+
} else {
|
|
398
|
+
// If the desired weight is inclusively between 400 and 500...
|
|
399
|
+
if (400.0..=500.0).contains(&weight) {
|
|
400
|
+
// weights greater than or equal to the target weight are checked in ascending
|
|
401
|
+
// order until 500 is hit and checked
|
|
402
|
+
if let Some(found) = set
|
|
403
|
+
.iter()
|
|
404
|
+
.enumerate()
|
|
405
|
+
.filter(|f| f.1.weight >= weight && f.1.weight <= 500.0)
|
|
406
|
+
.min_by(|x, y| x.1.weight.partial_cmp(&y.1.weight).unwrap_or(Less))
|
|
407
|
+
{
|
|
408
|
+
return Some(found.1.index);
|
|
409
|
+
}
|
|
410
|
+
// followed by weights less than the target weight in descending order
|
|
411
|
+
if let Some(found) = set
|
|
412
|
+
.iter()
|
|
413
|
+
.enumerate()
|
|
414
|
+
.filter(|f| f.1.weight < weight)
|
|
415
|
+
.max_by(|x, y| x.1.weight.partial_cmp(&y.1.weight).unwrap_or(Less))
|
|
416
|
+
{
|
|
417
|
+
return Some(found.1.index);
|
|
418
|
+
}
|
|
419
|
+
// followed by weights greater than 500, until a match is found.
|
|
420
|
+
if let Some(found) = set
|
|
421
|
+
.iter()
|
|
422
|
+
.enumerate()
|
|
423
|
+
.filter(|f| f.1.weight > 500.0)
|
|
424
|
+
.min_by(|x, y| x.1.weight.partial_cmp(&y.1.weight).unwrap_or(Less))
|
|
425
|
+
{
|
|
426
|
+
return Some(found.1.index);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// If the desired weight is less than 400...
|
|
430
|
+
else if weight < 400.0 {
|
|
431
|
+
// weights less than or equal to the target weight are checked in descending
|
|
432
|
+
if let Some(found) = set
|
|
433
|
+
.iter()
|
|
434
|
+
.filter(|f| f.weight <= weight)
|
|
435
|
+
.max_by(|x, y| x.weight.partial_cmp(&y.weight).unwrap_or(Less))
|
|
436
|
+
{
|
|
437
|
+
return Some(found.index);
|
|
438
|
+
}
|
|
439
|
+
// followed by weights greater than the target weight in ascending order
|
|
440
|
+
if let Some(found) = set
|
|
441
|
+
.iter()
|
|
442
|
+
.filter(|f| f.weight > weight)
|
|
443
|
+
.min_by(|x, y| x.weight.partial_cmp(&y.weight).unwrap_or(Less))
|
|
444
|
+
{
|
|
445
|
+
return Some(found.index);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
// If the desired weight is greater than 500...
|
|
449
|
+
else {
|
|
450
|
+
// weights greater than or equal to the target weight are checked in ascending
|
|
451
|
+
if let Some(found) = set
|
|
452
|
+
.iter()
|
|
453
|
+
.filter(|f| f.weight >= weight)
|
|
454
|
+
.min_by(|x, y| x.weight.partial_cmp(&y.weight).unwrap_or(Less))
|
|
455
|
+
{
|
|
456
|
+
return Some(found.index);
|
|
457
|
+
}
|
|
458
|
+
// followed by weights less than the target weight in descending order
|
|
459
|
+
if let Some(found) = set
|
|
460
|
+
.iter()
|
|
461
|
+
.filter(|f| f.weight < weight)
|
|
462
|
+
.max_by(|x, y| x.weight.partial_cmp(&y.weight).unwrap_or(Less))
|
|
463
|
+
{
|
|
464
|
+
return Some(found.index);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
None
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
fn oblique_angle(style: FontStyle) -> Option<f32> {
|
|
472
|
+
match style {
|
|
473
|
+
FontStyle::Oblique(angle) => Some(angle.unwrap_or(DEFAULT_OBLIQUE_ANGLE)),
|
|
474
|
+
_ => None,
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
fn oblique_style(style: FontStyle) -> Option<(FontStyle, f32)> {
|
|
479
|
+
match style {
|
|
480
|
+
FontStyle::Oblique(angle) => Some((style, angle.unwrap_or(DEFAULT_OBLIQUE_ANGLE))),
|
|
481
|
+
_ => None,
|
|
482
|
+
}
|
|
483
|
+
}
|