Skip to content

Commit 905b344

Browse files
ollimeierOlli Meier
andauthored
refactor(family_and_style_max_length): add context and improve report (#566)
* refactor(family_and_style_max_length): add info '({} characters too long)' * refactor(required_name_ids): removing leftover print * refactor(family_and_style_max_length): adding unittest + context * refactor(family_and_style_max_length): add missing context "INSTANCE_NAME" --------- Co-authored-by: Olli Meier <olli.meier@productiontype.com>
1 parent c69d124 commit 905b344

File tree

2 files changed

+136
-17
lines changed

2 files changed

+136
-17
lines changed

profile-universal/src/checks/name/family_and_style_max_length.rs

Lines changed: 136 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,55 @@ fn low_level_names(name: &Name<'_>, name_id: NameId) -> HashMap<(u16, u16, u16),
3737
proposal = "https://github.com/fonttools/fontbakery/issues/2179",
3838
title = "Combined length of family and style must not exceed 32 characters."
3939
)]
40-
fn family_and_style_max_length(t: &Testable, _context: &Context) -> CheckFnResult {
40+
fn family_and_style_max_length(t: &Testable, context: &Context) -> CheckFnResult {
4141
let f = testfont!(t);
42+
if !f.has_table(b"name") {
43+
return Ok(Status::just_one_fail("lacks-table", "No name table."));
44+
}
45+
let config = context.local_config("name/family_and_style_max_length");
46+
let full_name_length: usize = config
47+
.get("FULL_NAME")
48+
.and_then(|v| v.as_u64())
49+
.unwrap_or(32) as usize;
50+
51+
let postscript_name_length: usize = config
52+
.get("POSTSCRIPT_NAME")
53+
.and_then(|v| v.as_u64())
54+
.unwrap_or(27) as usize;
55+
56+
let instance_name_length: usize = config
57+
.get("INSTANCE_NAME")
58+
.and_then(|v| v.as_u64())
59+
.unwrap_or(32) as usize;
60+
4261
let mut problems = vec![];
43-
if f.get_name_entry_strings(NameId::FULL_NAME)
44-
.any(|name| strip_ribbi(&name).len() > 32)
45-
{
46-
problems.push(Status::fail(
62+
for name in f.get_name_entry_strings(NameId::FULL_NAME) {
63+
if strip_ribbi(&name).len() > full_name_length {
64+
let chars_too_long_count = strip_ribbi(&name).len() - full_name_length;
65+
let chars_too_long = chars_too_long_count.to_string();
66+
problems.push(Status::fail(
4767
"nameid4-too-long",
48-
"Name ID 4 'Full Font Name' exceeds 32 characters. This has been found to cause problems with the dropdown menu in old versions of Microsoft Word as well as shaping issues for some accented letters in Microsoft Word on Windows 10 and 11.",
68+
&format!(
69+
"Name ID 4 'Full Font Name' exceeds {} characters ({} characters too long). This has been found to cause problems with the dropdown menu in old versions of Microsoft Word as well as shaping issues for some accented letters in Microsoft Word on Windows 10 and 11.",
70+
full_name_length,
71+
chars_too_long
72+
),
4973
));
74+
}
5075
}
51-
if f.get_name_entry_strings(NameId::POSTSCRIPT_NAME)
52-
.any(|name| name.len() > 27)
53-
{
54-
problems.push(Status::warn(
55-
"nameid6-too-long",
56-
"Name ID 6 'PostScript Name' exceeds 27 characters. This has been found to cause problems with PostScript printers, especially on Mac platforms.",
57-
));
76+
for name in f.get_name_entry_strings(NameId::POSTSCRIPT_NAME) {
77+
if name.len() > postscript_name_length {
78+
let chars_too_long_count = name.len() - postscript_name_length;
79+
let chars_too_long = chars_too_long_count.to_string();
80+
problems.push(Status::warn(
81+
"nameid6-too-long",
82+
&format!(
83+
"Name ID 6 'PostScript Name' exceeds {} characters ({} characters too long). This has been found to cause problems with PostScript printers, especially on Mac platforms.",
84+
postscript_name_length,
85+
chars_too_long
86+
),
87+
));
88+
}
5889
}
5990
let name = f.font().name()?;
6091
let typo_family_names: HashMap<(u16, u16, u16), String> =
@@ -69,14 +100,18 @@ fn family_and_style_max_length(t: &Testable, _context: &Context) -> CheckFnResul
69100
// Use typo if present, nameid=1 otherwise
70101
let family_name = typo_family_names.get(key).unwrap_or(string);
71102
let full_instance_name = format!("{family_name} {instance_name}");
72-
if full_instance_name.len() > 32 {
103+
if full_instance_name.len() > instance_name_length {
104+
let chars_too_long_count = full_instance_name.len() - instance_name_length;
105+
let chars_too_long = chars_too_long_count.to_string();
73106
problems.push(Status::fail(
74107
"instance-too-long",
75108
&format!(
76-
"Variable font instance name '{}' formed by space-separated concatenation of font family name (nameID {}) and instance subfamily nameID {} exceeds 32 characters.\n\nThis has been found to cause shaping issues for some accented letters in Microsoft Word on Windows 10 and 11.",
109+
"Variable font instance name '{}' formed by space-separated concatenation of font family name (nameID {}) and instance subfamily nameID {} exceeds {} characterss ({} characters too long).\n\nThis has been found to cause shaping issues for some accented letters in Microsoft Word on Windows 10 and 11.",
77110
full_instance_name,
78111
NameId::FAMILY_NAME,
79-
instance_name
112+
instance_name,
113+
instance_name_length,
114+
chars_too_long
80115
),
81116
));
82117
}
@@ -87,3 +122,88 @@ fn family_and_style_max_length(t: &Testable, _context: &Context) -> CheckFnResul
87122

88123
return_result(problems)
89124
}
125+
126+
#[cfg(test)]
127+
mod tests {
128+
#![allow(clippy::unwrap_used, clippy::expect_used)]
129+
130+
use fontspector_checkapi::{
131+
codetesting::{
132+
assert_messages_contain, assert_pass, assert_results_contain, run_check_with_config,
133+
test_able,
134+
},
135+
StatusCode, TestableType,
136+
};
137+
use std::collections::HashMap;
138+
139+
#[test]
140+
fn test_family_and_style_max_length_fail_nid4() {
141+
let conf = HashMap::from([(
142+
"name/family_and_style_max_length".to_string(),
143+
serde_json::json!({ "FULL_NAME": 3}),
144+
)]);
145+
let testable = test_able("varfont/inter/Inter[slnt,wght].ttf");
146+
let results = run_check_with_config(
147+
super::family_and_style_max_length,
148+
TestableType::Single(&testable),
149+
conf,
150+
);
151+
assert_messages_contain(&results, "(2 characters too long)");
152+
assert_results_contain(
153+
&results,
154+
StatusCode::Fail,
155+
Some("nameid4-too-long".to_string()),
156+
);
157+
}
158+
159+
#[test]
160+
fn test_family_and_style_max_length_fail_nid6() {
161+
let conf = HashMap::from([(
162+
"name/family_and_style_max_length".to_string(),
163+
serde_json::json!({ "POSTSCRIPT_NAME": 11}),
164+
)]);
165+
let testable = test_able("varfont/inter/Inter[slnt,wght].ttf");
166+
let results = run_check_with_config(
167+
super::family_and_style_max_length,
168+
TestableType::Single(&testable),
169+
conf,
170+
);
171+
assert_messages_contain(&results, "(2 characters too long)");
172+
assert_results_contain(
173+
&results,
174+
StatusCode::Warn,
175+
Some("nameid6-too-long".to_string()),
176+
);
177+
}
178+
179+
#[test]
180+
fn test_family_and_style_max_length_fail_instance_name() {
181+
let conf = HashMap::from([(
182+
"name/family_and_style_max_length".to_string(),
183+
serde_json::json!({ "INSTANCE_NAME": 11}),
184+
)]);
185+
let testable = test_able("varfont/inter/Inter[slnt,wght].ttf");
186+
let results = run_check_with_config(
187+
super::family_and_style_max_length,
188+
TestableType::Single(&testable),
189+
conf,
190+
);
191+
assert_messages_contain(&results, "(6 characters too long)");
192+
assert_results_contain(
193+
&results,
194+
StatusCode::Fail,
195+
Some("instance-too-long".to_string()),
196+
);
197+
}
198+
199+
#[test]
200+
fn test_family_and_style_max_length_pass_no_config() {
201+
let testable = test_able("varfont/inter/Inter[slnt,wght].ttf");
202+
let results = run_check_with_config(
203+
super::family_and_style_max_length,
204+
TestableType::Single(&testable),
205+
HashMap::new(),
206+
);
207+
assert_pass(&results);
208+
}
209+
}

profile-universal/src/checks/required_name_ids.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use std::vec;
1414
title = "Required name ids in name table"
1515
)]
1616
fn required_name_ids(t: &Testable, context: &Context) -> CheckFnResult {
17-
print!("required_name_ids check running...");
1817
let font = testfont!(t);
1918
if !font.has_table(b"name") {
2019
return Ok(Status::just_one_fail("lacks-table", "No name table."));

0 commit comments

Comments
 (0)