|
1 | 1 | use std::collections::HashSet; |
2 | 2 |
|
3 | 3 | use fontations::skrifa::raw::{types::Version16Dot16, TableProvider}; |
4 | | -use fontspector_checkapi::{prelude::*, skip, testfont, FileTypeConvert}; |
| 4 | +use fontspector_checkapi::{prelude::*, skip, testfont, FileTypeConvert, Source, SourceFile}; |
5 | 5 | use itertools::Itertools; |
6 | 6 |
|
7 | 7 | enum NameValidity { |
@@ -49,7 +49,8 @@ fn test_glyph_name(s: &str) -> NameValidity { |
49 | 49 | https://github.com/adobe-type-tools/agl-specification |
50 | 50 | |
51 | 51 | Glyph names must also be unique, as duplicate glyph names prevent font installation on Mac OS X.", |
52 | | - proposal = "https://github.com/fonttools/fontbakery/issues/2832" |
| 52 | + proposal = "https://github.com/fonttools/fontbakery/issues/2832", |
| 53 | + fix_source = sourcefix_valid_glyphnames, |
53 | 54 | )] |
54 | 55 | fn valid_glyphnames(f: &Testable, _context: &Context) -> CheckFnResult { |
55 | 56 | let font = testfont!(f); |
@@ -169,3 +170,58 @@ fn valid_glyphnames(f: &Testable, _context: &Context) -> CheckFnResult { |
169 | 170 |
|
170 | 171 | return_result(problems) |
171 | 172 | } |
| 173 | + |
| 174 | +fn sourcefix_valid_glyphnames(s: &mut SourceFile) -> FixFnResult { |
| 175 | + fn fix_a_ufo(font: &mut norad::Font) -> FixFnResult { |
| 176 | + let mut changed = false; |
| 177 | + let mut renames = vec![]; |
| 178 | + let layer = font.default_layer_mut(); |
| 179 | + if let Some(space_glyph) = layer |
| 180 | + .iter() |
| 181 | + .find(|g| g.codepoints.contains(' ')) |
| 182 | + .map(|x| x.name().as_str()) |
| 183 | + { |
| 184 | + if space_glyph != "space" { |
| 185 | + renames.push((space_glyph.to_string(), "space")); |
| 186 | + } |
| 187 | + } |
| 188 | + if let Some(nbspace_glyph) = layer |
| 189 | + .iter() |
| 190 | + .find(|g| g.codepoints.contains(0xa0 as char)) |
| 191 | + .map(|x| x.name().as_str()) |
| 192 | + { |
| 193 | + if nbspace_glyph != "nbspace" { |
| 194 | + renames.push((nbspace_glyph.to_string(), "nbspace")); |
| 195 | + } |
| 196 | + } |
| 197 | + for (old_name, new_name) in renames { |
| 198 | + layer.rename_glyph(&old_name, new_name, true).map_err(|e| { |
| 199 | + FontspectorError::Fix(format!( |
| 200 | + "Failed to rename glyph {old_name} to {new_name}: {e}" |
| 201 | + )) |
| 202 | + })?; |
| 203 | + changed = true; |
| 204 | + } |
| 205 | + |
| 206 | + Ok(changed) |
| 207 | + } |
| 208 | + match s.source { |
| 209 | + Source::Ufo(ref mut font) => fix_a_ufo(font), |
| 210 | + Source::Designspace(ref mut ds) => ds.apply_fix(&fix_a_ufo), |
| 211 | + Source::Glyphs(ref mut font) => { |
| 212 | + let font = font.font_mut(); |
| 213 | + let mut changed = false; |
| 214 | + for glyph in font.glyphs_mut().iter_mut() { |
| 215 | + if glyph.unicode().contains(&0x20u32) && glyph.name() != "space" { |
| 216 | + glyph.set_name("space".to_string()); |
| 217 | + changed = true; |
| 218 | + } |
| 219 | + if glyph.unicode().contains(&0xa0u32) && glyph.name() != "nbspace" { |
| 220 | + glyph.set_name("nbspace".to_string()); |
| 221 | + changed = true; |
| 222 | + } |
| 223 | + } |
| 224 | + Ok(changed) |
| 225 | + } |
| 226 | + } |
| 227 | +} |
0 commit comments