Skip to content

Commit e49cfed

Browse files
authored
Merge pull request #2 from felipesanches/new_check_arabic_spacing_symbols
new check: arabic_spacing_symbols
2 parents b8c42b4 + c19cb45 commit e49cfed

File tree

6 files changed

+112
-3
lines changed

6 files changed

+112
-3
lines changed

fontspector-checkapi/src/constants.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1 +1,20 @@
11
// pub const RIBBI_STYLE_NAMES: [&str; 5] = ["Regular", "Italic", "Bold", "BoldItalic", "Bold Italic"];
2+
3+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4+
pub enum GlyphClass {
5+
Base,
6+
Ligature,
7+
Mark,
8+
Component,
9+
}
10+
impl GlyphClass {
11+
pub fn from_u16(class: u16) -> Option<Self> {
12+
match class {
13+
1 => Some(Self::Base),
14+
2 => Some(Self::Ligature),
15+
3 => Some(Self::Mark),
16+
4 => Some(Self::Component),
17+
_ => None,
18+
}
19+
}
20+
}

fontspector-checkapi/src/font.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
use crate::{filetype::FileTypeConvert, FileType, Testable};
1+
use crate::{constants::GlyphClass, filetype::FileTypeConvert, CheckError, FileType, Testable};
22
use read_fonts::{
3+
tables::cmap::Cmap,
4+
tables::gdef::Gdef,
35
tables::{os2::SelectionFlags, post::DEFAULT_GLYPH_NAMES},
46
types::Version16Dot16,
57
TableProvider,
@@ -66,7 +68,32 @@ impl TestFont<'_> {
6668
self.font().table_data(Tag::new(table)).is_some()
6769
}
6870

69-
pub fn get_os2_fsselection(&self) -> Result<SelectionFlags, Box<dyn Error>> {
71+
pub fn get_cmap(&self) -> Result<Cmap, CheckError> {
72+
let cmap = self
73+
.font()
74+
.cmap()
75+
.map_err(|_| CheckError::Error("Font lacks a cmap table".to_string()))?;
76+
Ok(cmap)
77+
}
78+
79+
pub fn get_gdef(&self) -> Result<Gdef, CheckError> {
80+
let gdef = self
81+
.font()
82+
.gdef()
83+
.map_err(|_| CheckError::Error("Font lacks a GDEF table".to_string()))?;
84+
Ok(gdef)
85+
}
86+
87+
pub fn gdef_class(&self, glyph_id: GlyphId) -> Option<GlyphClass> {
88+
self.get_gdef()
89+
.ok()
90+
.and_then(|gdef| gdef.glyph_class_def())?
91+
.ok()
92+
.map(|class_def| class_def.get(glyph_id))
93+
.and_then(GlyphClass::from_u16)
94+
}
95+
96+
pub fn get_os2_fsselection(&self) -> Result<SelectionFlags, CheckError> {
7097
let os2 = self.font().os2()?;
7198
Ok(os2.fs_selection())
7299
}

fontspector-checkapi/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![deny(clippy::unwrap_used, clippy::expect_used)]
22
mod check;
33
mod checkresult;
4-
mod constants;
4+
pub mod constants;
55
mod context;
66
mod filetype;
77
mod font;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use fontspector_checkapi::constants::GlyphClass;
2+
use fontspector_checkapi::{prelude::*, testfont, FileTypeConvert};
3+
4+
const ARABIC_SPACING_SYMBOLS: [u16; 17] = [
5+
0xFBB2, // Dot Above
6+
0xFBB3, // Dot Below
7+
0xFBB4, // Two Dots Above
8+
0xFBB5, // Two Dots Below
9+
0xFBB6, // Three Dots Above
10+
0xFBB7, // Three Dots Below
11+
0xFBB8, // Three Dots Pointing Downwards Above
12+
0xFBB9, // Three Dots Pointing Downwards Below
13+
0xFBBA, // Four Dots Above
14+
0xFBBB, // Four Dots Below
15+
0xFBBC, // Double Vertical Bar Below
16+
0xFBBD, // Two Dots Vertically Above
17+
0xFBBE, // Two Dots Vertically Below
18+
0xFBBF, // Ring
19+
0xFBC0, // Small Tah Above
20+
0xFBC1, // Small Tah Below
21+
0xFBC2, // Wasla Above
22+
];
23+
24+
#[check(
25+
id = "com.google.fonts/check/arabic_spacing_symbols",
26+
title = "Check that Arabic spacing symbols U+FBB2–FBC1 aren't classified as marks.",
27+
rationale = "
28+
Unicode has a few spacing symbols representing Arabic dots and other marks,
29+
but they are purposefully not classified as marks.
30+
31+
Many fonts mistakenly classify them as marks, making them unsuitable
32+
for their original purpose as stand-alone symbols to used in pedagogical
33+
contexts discussing Arabic consonantal marks.
34+
",
35+
proposal = "https://github.com/googlefonts/fontbakery/issues/4295"
36+
)]
37+
fn arabic_spacing_symbols(t: &Testable, _context: &Context) -> CheckFnResult {
38+
let mut problems: Vec<Status> = vec![];
39+
let f = testfont!(t);
40+
let cmap = f.get_cmap()?;
41+
42+
for codepoint in ARABIC_SPACING_SYMBOLS {
43+
if let Some(gid) = cmap.map_codepoint(codepoint) {
44+
if f.gdef_class(gid) == Some(GlyphClass::Mark) {
45+
problems.push(Status::fail(
46+
"gdef-mark",
47+
&format!(
48+
"U+{:04X} is defined in GDEF as a mark (class 3).",
49+
codepoint
50+
),
51+
));
52+
}
53+
}
54+
}
55+
56+
if problems.is_empty() {
57+
Ok(Status::just_one_pass())
58+
} else {
59+
return_result(problems)
60+
}
61+
}

profile-universal/src/checks/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod arabic_spacing_symbols;
12
pub mod bold_italic_unique;
23
pub mod fvar;
34
pub mod glyphnames;

profile-universal/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub struct Universal;
66

77
impl fontspector_checkapi::Plugin for Universal {
88
fn register(&self, cr: &mut Registry) -> Result<(), String> {
9+
cr.register_check(checks::arabic_spacing_symbols::arabic_spacing_symbols);
910
cr.register_check(checks::fvar::axis_ranges_correct);
1011
cr.register_check(checks::fvar::regular_coords_correct);
1112
cr.register_check(checks::glyphnames::valid_glyphnames);

0 commit comments

Comments
 (0)