This follows CSS Fonts Level 3 § 5.2 [1]. https://drafts.csswg.org/css-fonts-3/#font-style-matching
(
candidates: &[Properties],
query: &Properties,
)
| 20 | /// |
| 21 | /// https://drafts.csswg.org/css-fonts-3/#font-style-matching |
| 22 | pub fn find_best_match( |
| 23 | candidates: &[Properties], |
| 24 | query: &Properties, |
| 25 | ) -> Result<usize, SelectionError> { |
| 26 | // Step 4. |
| 27 | let mut matching_set: Vec<usize> = (0..candidates.len()).collect(); |
| 28 | if matching_set.is_empty() { |
| 29 | return Err(SelectionError::NotFound); |
| 30 | } |
| 31 | |
| 32 | // Step 4a (`font-stretch`). |
| 33 | let matching_stretch = if matching_set |
| 34 | .iter() |
| 35 | .any(|&index| candidates[index].stretch == query.stretch) |
| 36 | { |
| 37 | // Exact match. |
| 38 | query.stretch |
| 39 | } else if query.stretch <= Stretch::NORMAL { |
| 40 | // Closest width, first checking narrower values and then wider values. |
| 41 | match matching_set |
| 42 | .iter() |
| 43 | .filter(|&&index| candidates[index].stretch < query.stretch) |
| 44 | .min_by_key(|&&index| FloatOrd(query.stretch.0 - candidates[index].stretch.0)) |
| 45 | { |
| 46 | Some(&matching_index) => candidates[matching_index].stretch, |
| 47 | None => { |
| 48 | let matching_index = *matching_set |
| 49 | .iter() |
| 50 | .min_by_key(|&&index| FloatOrd(candidates[index].stretch.0 - query.stretch.0)) |
| 51 | .unwrap(); |
| 52 | candidates[matching_index].stretch |
| 53 | } |
| 54 | } |
| 55 | } else { |
| 56 | // Closest width, first checking wider values and then narrower values. |
| 57 | match matching_set |
| 58 | .iter() |
| 59 | .filter(|&&index| candidates[index].stretch > query.stretch) |
| 60 | .min_by_key(|&&index| FloatOrd(candidates[index].stretch.0 - query.stretch.0)) |
| 61 | { |
| 62 | Some(&matching_index) => candidates[matching_index].stretch, |
| 63 | None => { |
| 64 | let matching_index = *matching_set |
| 65 | .iter() |
| 66 | .min_by_key(|&&index| FloatOrd(query.stretch.0 - candidates[index].stretch.0)) |
| 67 | .unwrap(); |
| 68 | candidates[matching_index].stretch |
| 69 | } |
| 70 | } |
| 71 | }; |
| 72 | matching_set.retain(|&index| candidates[index].stretch == matching_stretch); |
| 73 | |
| 74 | // Step 4b (`font-style`). |
| 75 | let style_preference = match query.style { |
| 76 | Style::Italic => [Style::Italic, Style::Oblique, Style::Normal], |
| 77 | Style::Oblique => [Style::Oblique, Style::Italic, Style::Normal], |
| 78 | Style::Normal => [Style::Normal, Style::Oblique, Style::Italic], |
| 79 | }; |
no test coverage detected