Skip to content

Commit 20d9a48

Browse files
committed
Move to the hellish procmacro
1 parent c126b30 commit 20d9a48

File tree

13 files changed

+172
-247
lines changed

13 files changed

+172
-247
lines changed

profile-googlefonts/src/family.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ use std::collections::HashSet;
33

44
use fontspector_checkapi::{prelude::*, FileTypeConvert};
55

6+
#[check(
7+
id = "com.google.fonts/check/family/equal_codepoint_coverage",
8+
title = "Fonts have equal codepoint coverage?",
9+
rationale = "For a given family, all fonts must have the same codepoint coverage.
10+
This is because we want to avoid the situation where, for example,
11+
a character is present in a regular font but missing in the italic
12+
style; turning on italic would cause the character to be rendered
13+
either as a fake italic (auto-slanted) or to show tofu.",
14+
proposal = "https://github.com/fonttools/fontbakery/issues/4180",
15+
implementation = "all"
16+
)]
617
fn family_equal_codepoint_coverage(c: &TestableCollection, _context: &Context) -> CheckFnResult {
718
let fonts = TTF.from_collection(c);
819
if fonts.len() < 2 {
@@ -54,19 +65,3 @@ fn family_equal_codepoint_coverage(c: &TestableCollection, _context: &Context) -
5465
}
5566
return_result(problems)
5667
}
57-
58-
pub const CHECK_FAMILY_EQUAL_CODEPOINT_COVERAGE: Check = Check {
59-
id: "com.google.fonts/check/family/equal_codepoint_coverage",
60-
title: "Fonts have equal codepoint coverage?",
61-
rationale: "For a given family, all fonts must have the same codepoint coverage.
62-
This is because we want to avoid the situation where, for example,
63-
a character is present in a regular font but missing in the italic
64-
style; turning on italic would cause the character to be rendered
65-
either as a fake italic (auto-slanted) or to show tofu.",
66-
proposal: "https://github.com/fonttools/fontbakery/issues/4180",
67-
implementation: CheckImplementation::CheckAll(&family_equal_codepoint_coverage),
68-
applies_to: "TTF",
69-
hotfix: None,
70-
fix_source: None,
71-
flags: CheckFlags::default(),
72-
};

profile-googlefonts/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
#![deny(clippy::unwrap_used, clippy::expect_used)]
22
mod family;
33
mod metadata;
4-
use family::CHECK_FAMILY_EQUAL_CODEPOINT_COVERAGE;
54
use fontspector_checkapi::prelude::*;
6-
use metadata::CHECK_METADATA_PARSES;
75

86
pub struct GoogleFonts;
97
impl fontspector_checkapi::Plugin for GoogleFonts {
108
fn register(&self, cr: &mut Registry) -> Result<(), String> {
119
let mdpb = FileType::new("METADATA.pb");
1210
cr.register_filetype("MDPB", mdpb);
13-
cr.register_check(CHECK_FAMILY_EQUAL_CODEPOINT_COVERAGE);
14-
cr.register_check(CHECK_METADATA_PARSES);
11+
cr.register_check(family::family_equal_codepoint_coverage);
12+
cr.register_check(metadata::validate_metadatapb);
1513
let profile = Profile::from_toml(
1614
r#"
1715
include_profiles = ["universal"]

profile-googlefonts/src/metadata.rs

+10-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ use chrono::prelude::*;
55
use fonts_public::FamilyProto;
66
use fontspector_checkapi::prelude::*;
77

8+
#[check(
9+
id = "com.google.fonts/check/metadata/parses",
10+
title = "Check METADATA.pb parses correctly",
11+
rationale = "
12+
The purpose of this check is to ensure that the METADATA.pb file is not
13+
malformed.
14+
",
15+
proposal = "https://github.com/fonttools/fontbakery/issues/2248",
16+
applies_to = "MDPB"
17+
)]
818
fn validate_metadatapb(c: &Testable, _context: &Context) -> CheckFnResult {
919
let mdpb = std::str::from_utf8(&c.contents)
1020
.map_err(|_| CheckError::Error("METADATA.pb is not valid UTF-8".to_string()))?;
@@ -40,18 +50,3 @@ fn validate_metadatapb(c: &Testable, _context: &Context) -> CheckFnResult {
4050
}
4151
return_result(problems)
4252
}
43-
44-
pub const CHECK_METADATA_PARSES: Check = Check {
45-
id: "com.google.fonts/check/metadata/parses",
46-
title: "Check METADATA.pb parses correctly",
47-
rationale: "
48-
The purpose of this check is to ensure that the METADATA.pb file is not
49-
malformed.
50-
",
51-
proposal: "https://github.com/fonttools/fontbakery/issues/2248",
52-
implementation: CheckImplementation::CheckOne(&validate_metadatapb),
53-
applies_to: "MDPB",
54-
hotfix: None,
55-
fix_source: None,
56-
flags: CheckFlags::default(),
57-
};

profile-testplugin/src/lib.rs

+14-26
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,25 @@ use fontspector_checkapi::prelude::*;
33

44
struct Test;
55

6+
#[check(
7+
id = "com.google.fonts/check/test/say_hello",
8+
title = "Check that the plugin protocol is working",
9+
rationale = "This check is part of the example of how to create plugins.",
10+
proposal = "https://github.com/simoncozens/fontspector/commit/5fdf9750991176c8e2776557ce6c17c642c24a73"
11+
)]
612
fn say_hello(_c: &Testable, context: &Context) -> CheckFnResult {
713
println!("Hello from the test plugin!");
814
println!("My context was: {:?}", context);
915
return_result(vec![])
1016
}
1117

18+
#[check(
19+
id = "com.google.fonts/check/test/validate_toml",
20+
title = "Check that the filetype plugin protocol is working",
21+
rationale = "This check is part of the example of how to create plugins.",
22+
proposal = "https://github.com/simoncozens/fontspector/commit/5fdf9750991176c8e2776557ce6c17c642c24a73",
23+
applies_to = "TOML"
24+
)]
1225
fn validate_toml(c: &Testable, _context: &Context) -> CheckFnResult {
1326
let toml = std::fs::read_to_string(&c.filename)
1427
.map_err(|_| CheckError::Error("Couldn't open file".to_string()))?;
@@ -18,38 +31,13 @@ fn validate_toml(c: &Testable, _context: &Context) -> CheckFnResult {
1831
Status::just_one_fail("invalid-toml", "Invalid TOML")
1932
})
2033
}
21-
pub const SAY_HELLO: Check = Check {
22-
id: "com.google.fonts/check/test/say_hello",
23-
title: "Check that the plugin protocol is working",
24-
rationale: "This check is part of the example of how to create plugins.",
25-
proposal:
26-
"https://github.com/simoncozens/fontspector/commit/5fdf9750991176c8e2776557ce6c17c642c24a73",
27-
implementation: CheckImplementation::CheckOne(&say_hello),
28-
applies_to: "TTF",
29-
hotfix: None,
30-
fix_source: None,
31-
flags: CheckFlags::default(),
32-
};
33-
34-
pub const VALIDATE_TOML: Check = Check {
35-
id: "com.google.fonts/check/test/validate_toml",
36-
title: "Check that the filetype plugin protocol is working",
37-
rationale: "This check is part of the example of how to create plugins.",
38-
proposal:
39-
"https://github.com/simoncozens/fontspector/commit/5fdf9750991176c8e2776557ce6c17c642c24a73",
40-
implementation: CheckImplementation::CheckOne(&validate_toml),
41-
applies_to: "TOML",
42-
hotfix: None,
43-
fix_source: None,
44-
flags: CheckFlags::default(),
45-
};
4634

4735
impl fontspector_checkapi::Plugin for Test {
4836
fn register(&self, cr: &mut Registry) -> Result<(), String> {
4937
let toml = FileType::new("*.toml");
5038
cr.register_filetype("TOML", toml);
5139

52-
cr.register_simple_profile("test", vec![VALIDATE_TOML, SAY_HELLO])
40+
cr.register_simple_profile("test", vec![validate_toml, say_hello])
5341
}
5442
}
5543

profile-universal/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ authors = [
99

1010
[dependencies]
1111
fontspector-checkapi = { path = "../fontspector-checkapi" }
12+
fontspector-checkhelper = { workspace = true }
1213
read-fonts = {workspace = true}
1314
write-fonts = {workspace = true}
1415
font-types = {workspace = true}

profile-universal/src/checks/fvar.rs

+18-30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ const REGULAR_COORDINATE_EXPECTATIONS: [(&str, f32); 4] = [
88
("ital", 0.0),
99
];
1010

11+
#[check(
12+
id = "com.google.fonts/check/fvar/regular_coords_correct",
13+
title = "Axes and named instances fall within correct ranges?",
14+
rationale = "According to the Open-Type spec's registered design-variation tags, instances in a variable font should have certain prescribed values.
15+
If a variable font has a 'wght' (Weight) axis, the valid coordinate range is 1-1000.
16+
If a variable font has a 'wdth' (Width) axis, the valid numeric range is strictly greater than zero.
17+
If a variable font has a 'slnt' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.
18+
If a variable font has a 'ital' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.",
19+
proposal = "https://github.com/fonttools/fontbakery/issues/2572"
20+
)]
1121
fn regular_coords_correct(t: &Testable, _context: &Context) -> CheckFnResult {
1222
let f = testfont!(t);
1323
if !f.is_variable_font() {
@@ -50,22 +60,16 @@ fn regular_coords_correct(t: &Testable, _context: &Context) -> CheckFnResult {
5060
return_result(problems)
5161
}
5262

53-
pub const CHECK_REGULAR_COORDS_CORRECT: Check = Check {
54-
id: "com.google.fonts/check/fvar/regular_coords_correct",
55-
title: "Regular instance coordinates are correct?",
56-
rationale: "According to the Open-Type spec's registered design-variation tags, the Regular instance in a variable font should have certain prescribed values.
57-
If a variable font has a 'wght' (Weight) axis, then the coordinate of its 'Regular' instance is required to be 400.
58-
If a variable font has a 'wdth' (Width) axis, then the coordinate of its 'Regular' instance is required to be 100.
63+
#[check(
64+
id = "com.google.fonts/check/fvar/axis_ranges_correct",
65+
title = "Axes and named instances fall within correct ranges?",
66+
rationale = "According to the Open-Type spec's registered design-variation tags, instances in a variable font should have certain prescribed values.
67+
If a variable font has a 'wght' (Weight) axis, the valid coordinate range is 1-1000.
68+
If a variable font has a 'wdth' (Width) axis, the valid numeric range is strictly greater than zero.
5969
If a variable font has a 'slnt' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.
6070
If a variable font has a 'ital' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.",
61-
proposal: "https://github.com/fonttools/fontbakery/issues/1707",
62-
implementation: CheckImplementation::CheckOne(&regular_coords_correct),
63-
applies_to: "TTF",
64-
hotfix: None,
65-
fix_source: None,
66-
flags: CheckFlags::default(),
67-
};
68-
71+
proposal = "https://github.com/fonttools/fontbakery/issues/2572"
72+
)]
6973
fn axis_ranges_correct(t: &Testable, _context: &Context) -> CheckFnResult {
7074
let f = testfont!(t);
7175
if !f.is_variable_font() {
@@ -136,19 +140,3 @@ fn axis_ranges_correct(t: &Testable, _context: &Context) -> CheckFnResult {
136140
}
137141
return_result(problems)
138142
}
139-
140-
pub const CHECK_AXIS_RANGES_CORRECT: Check = Check {
141-
id: "com.google.fonts/check/fvar/axis_ranges_correct",
142-
title: "Axes and named instances fall within correct ranges?",
143-
rationale: "According to the Open-Type spec's registered design-variation tags, instances in a variable font should have certain prescribed values.
144-
If a variable font has a 'wght' (Weight) axis, the valid coordinate range is 1-1000.
145-
If a variable font has a 'wdth' (Width) axis, the valid numeric range is strictly greater than zero.
146-
If a variable font has a 'slnt' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.
147-
If a variable font has a 'ital' (Slant) axis, then the coordinate of its 'Regular' instance is required to be 0.",
148-
proposal: "https://github.com/fonttools/fontbakery/issues/2572",
149-
implementation: CheckImplementation::CheckOne(&axis_ranges_correct),
150-
applies_to: "TTF",
151-
hotfix: None,
152-
fix_source: None,
153-
flags: CheckFlags::default(),
154-
};

profile-universal/src/checks/glyphnames.rs

+24-30
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,30 @@ fn test_glyph_name(s: &str) -> NameValidity {
2929
NameValidity::OK
3030
}
3131

32+
#[check(
33+
id = "com.google.fonts/check/valid_glyphnames",
34+
title = "Glyph names are all valid?",
35+
rationale = "Microsoft's recommendations for OpenType Fonts states the following:
36+
37+
'NOTE: The PostScript glyph name must be no longer than 31 characters,
38+
include only uppercase or lowercase English letters, European digits,
39+
the period or the underscore, i.e. from the set `[A-Za-z0-9_.]` and
40+
should start with a letter, except the special glyph name `.notdef`
41+
which starts with a period.'
42+
43+
https://learn.microsoft.com/en-us/typography/opentype/otspec181/recom#-post--table
44+
45+
46+
In practice, though, particularly in modern environments, glyph names
47+
can be as long as 63 characters.
48+
49+
According to the \"Adobe Glyph List Specification\" available at:
50+
51+
https://github.com/adobe-type-tools/agl-specification
52+
53+
Glyph names must also be unique, as duplicate glyph names prevent font installation on Mac OS X.",
54+
proposal = "https://github.com/fonttools/fontbakery/issues/2832"
55+
)]
3256
fn valid_glyphnames(f: &Testable, _context: &Context) -> CheckFnResult {
3357
let font = testfont!(f);
3458
let mut problems: Vec<Status> = vec![];
@@ -145,33 +169,3 @@ fn valid_glyphnames(f: &Testable, _context: &Context) -> CheckFnResult {
145169

146170
return_result(problems)
147171
}
148-
149-
pub const CHECK_VALID_GLYPHNAMES: Check = Check {
150-
id: "com.google.fonts/check/valid_glyphnames",
151-
title: "Glyph names are all valid?",
152-
rationale: "Microsoft's recommendations for OpenType Fonts states the following:
153-
154-
'NOTE: The PostScript glyph name must be no longer than 31 characters,
155-
include only uppercase or lowercase English letters, European digits,
156-
the period or the underscore, i.e. from the set `[A-Za-z0-9_.]` and
157-
should start with a letter, except the special glyph name `.notdef`
158-
which starts with a period.'
159-
160-
https://learn.microsoft.com/en-us/typography/opentype/otspec181/recom#-post--table
161-
162-
163-
In practice, though, particularly in modern environments, glyph names
164-
can be as long as 63 characters.
165-
166-
According to the \"Adobe Glyph List Specification\" available at:
167-
168-
https://github.com/adobe-type-tools/agl-specification
169-
170-
Glyph names must also be unique, as duplicate glyph names prevent font installation on Mac OS X.",
171-
proposal: "https://github.com/fonttools/fontbakery/issues/2832",
172-
implementation: CheckImplementation::CheckOne(&valid_glyphnames),
173-
applies_to: "TTF",
174-
hotfix: None,
175-
fix_source: None,
176-
flags: CheckFlags::default(),
177-
};

profile-universal/src/checks/hhea.rs

+25-37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use fontspector_checkapi::{prelude::*, testfont, FileTypeConvert};
22
use read_fonts::TableProvider;
33

4+
#[check(
5+
id = "com.google.fonts/check/maxadvancewidth",
6+
title = "MaxAdvanceWidth is consistent with values in the Hmtx and Hhea tables?",
7+
rationale = "The 'hhea' table contains a field which specifies the maximum advance width. This value should be consistent with the maximum advance width of all glyphs specified in the 'hmtx' table.",
8+
proposal = "legacy:check/073"
9+
)]
410
fn maxadvancewidth(t: &Testable, _context: &Context) -> CheckFnResult {
511
let f = testfont!(t);
612
let hhea_advance_width_max = f.font().hhea()?.advance_width_max().to_u16();
@@ -25,18 +31,26 @@ fn maxadvancewidth(t: &Testable, _context: &Context) -> CheckFnResult {
2531
})
2632
}
2733

28-
pub const CHECK_MAXADVANCEWIDTH: Check = Check {
29-
id: "com.google.fonts/check/maxadvancewidth",
30-
title: "MaxAdvanceWidth is consistent with values in the Hmtx and Hhea tables?",
31-
rationale: "The 'hhea' table contains a field which specifies the maximum advance width. This value should be consistent with the maximum advance width of all glyphs specified in the 'hmtx' table.",
32-
proposal: "legacy:check/073",
33-
implementation: CheckImplementation::CheckOne(&maxadvancewidth),
34-
applies_to: "TTF",
35-
hotfix: None,
36-
fix_source: None,
37-
flags: CheckFlags::default(),
38-
};
34+
#[check(
35+
id = "com.google.fonts/check/caret_slope",
36+
title = "Check hhea.caretSlopeRise and hhea.caretSlopeRun",
37+
proposal = "https://github.com/fonttools/fontbakery/issues/3670",
38+
rationale = r#"
39+
Checks whether hhea.caretSlopeRise and hhea.caretSlopeRun
40+
match with post.italicAngle.
3941
42+
For Upright fonts, you can set hhea.caretSlopeRise to 1
43+
and hhea.caretSlopeRun to 0.
44+
45+
For Italic fonts, you can set hhea.caretSlopeRise to head.unitsPerEm
46+
and calculate hhea.caretSlopeRun like this:
47+
round(math.tan(
48+
math.radians(-1 * font["post"].italicAngle)) * font["head"].unitsPerEm)
49+
50+
This check allows for a 0.1° rounding difference between the Italic angle
51+
as calculated by the caret slope and post.italicAngle
52+
"#
53+
)]
4054
fn caret_slope(t: &Testable, _context: &Context) -> CheckFnResult {
4155
let f = testfont!(t);
4256
let post_italic_angle = f.font().post()?.italic_angle().to_f32();
@@ -64,29 +78,3 @@ fn caret_slope(t: &Testable, _context: &Context) -> CheckFnResult {
6478
}
6579
Ok(Status::just_one_pass())
6680
}
67-
68-
pub const CHECK_CARET_SLOPE: Check = Check {
69-
id: "com.google.fonts/check/caret_slope",
70-
title: "Check hhea.caretSlopeRise and hhea.caretSlopeRun",
71-
rationale: r#"
72-
Checks whether hhea.caretSlopeRise and hhea.caretSlopeRun
73-
match with post.italicAngle.
74-
75-
For Upright fonts, you can set hhea.caretSlopeRise to 1
76-
and hhea.caretSlopeRun to 0.
77-
78-
For Italic fonts, you can set hhea.caretSlopeRise to head.unitsPerEm
79-
and calculate hhea.caretSlopeRun like this:
80-
round(math.tan(
81-
math.radians(-1 * font["post"].italicAngle)) * font["head"].unitsPerEm)
82-
83-
This check allows for a 0.1° rounding difference between the Italic angle
84-
as calculated by the caret slope and post.italicAngle
85-
"#,
86-
proposal: "https://github.com/fonttools/fontbakery/issues/3670",
87-
implementation: CheckImplementation::CheckOne(&caret_slope),
88-
applies_to: "TTF",
89-
hotfix: None,
90-
fix_source: None,
91-
flags: CheckFlags::default(),
92-
};

0 commit comments

Comments
 (0)