-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
further splitting out checks into individual .py files
- Loading branch information
1 parent
36d7423
commit 9689c8d
Showing
67 changed files
with
2,056 additions
and
2,017 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from fontbakery.prelude import FAIL, Message, check | ||
|
||
|
||
@check( | ||
id="STAT_in_statics", | ||
conditions=["not is_variable_font", "has_STAT_table"], | ||
rationale=""" | ||
Adobe feature syntax allows for the definition of a STAT table. Fonts built | ||
with a hand-coded STAT table in feature syntax may be built either as static | ||
or variable, but will end up with the same STAT table. | ||
This is a problem, because a STAT table which works on variable fonts | ||
will not be appropriate for static instances. The examples in the OpenType spec | ||
of non-variable fonts with a STAT table show that the table entries must be | ||
restricted to those entries which refer to the static font's position in | ||
the designspace. i.e. a Regular weight static should only have the following | ||
entry for the weight axis: | ||
<AxisIndex value="0"/> | ||
<Flags value="2"/> <!-- ElidableAxisValueName --> | ||
<ValueNameID value="265"/> <!-- Regular --> | ||
<Value value="400.0"/> | ||
However, if the STAT table intended for a variable font is compiled into a | ||
static, it will have many entries for this axis. In this case, Windows will | ||
read the first entry only, causing all instances to report themselves | ||
as "Thin Condensed". | ||
""", | ||
proposal="https://github.com/fonttools/fontbakery/issues/4149", | ||
) | ||
def check_STAT_in_statics(ttFont): | ||
"""Checking STAT table entries in static fonts.""" | ||
|
||
entries = {} | ||
|
||
def count_entries(tag_name): | ||
if tag_name in entries: | ||
entries[tag_name] += 1 | ||
else: | ||
entries[tag_name] = 1 | ||
|
||
stat = ttFont["STAT"].table | ||
designAxes = stat.DesignAxisRecord.Axis | ||
for axisValueTable in stat.AxisValueArray.AxisValue: | ||
axisValueFormat = axisValueTable.Format | ||
if axisValueFormat in (1, 2, 3): | ||
axisTag = designAxes[axisValueTable.AxisIndex].AxisTag | ||
count_entries(axisTag) | ||
elif axisValueFormat == 4: | ||
for rec in axisValueTable.AxisValueRecord: | ||
axisTag = designAxes[rec.AxisIndex].AxisTag | ||
count_entries(axisTag) | ||
|
||
for tag_name in entries: | ||
if entries[tag_name] > 1: | ||
yield FAIL, Message( | ||
"multiple-STAT-entries", | ||
"The STAT table has more than a single entry for the" | ||
f" '{tag_name}' axis ({entries[tag_name]}) on this" | ||
" static font which will causes problems on Windows.", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from fontbakery.prelude import FAIL, Message, check | ||
|
||
|
||
@check( | ||
id="STAT_strings", | ||
conditions=["has_STAT_table"], | ||
rationale=""" | ||
On the STAT table, the "Italic" keyword must not be used on AxisValues | ||
for variation axes other than 'ital'. | ||
""", | ||
proposal="https://github.com/fonttools/fontbakery/issues/2863", | ||
) | ||
def check_STAT_strings(ttFont): | ||
"""Check correctness of STAT table strings""" | ||
ital_axis_index = None | ||
for index, axis in enumerate(ttFont["STAT"].table.DesignAxisRecord.Axis): | ||
if axis.AxisTag == "ital": | ||
ital_axis_index = index | ||
break | ||
|
||
nameIDs = set() | ||
if ttFont["STAT"].table.AxisValueArray: | ||
for value in ttFont["STAT"].table.AxisValueArray.AxisValue: | ||
if hasattr(value, "AxisIndex"): | ||
if value.AxisIndex != ital_axis_index: | ||
nameIDs.add(value.ValueNameID) | ||
|
||
if hasattr(value, "AxisValueRecord"): | ||
for record in value.AxisValueRecord: | ||
if record.AxisIndex != ital_axis_index: | ||
nameIDs.add(value.ValueNameID) | ||
|
||
bad_values = set() | ||
for name in ttFont["name"].names: | ||
if name.nameID in nameIDs and "italic" in name.toUnicode().lower(): | ||
bad_values.add(f"nameID {name.nameID}: {name.toUnicode()}") | ||
|
||
if bad_values: | ||
yield FAIL, Message( | ||
"bad-italic", | ||
"The following AxisValue entries on the STAT table" | ||
f' should not contain "Italic":\n{sorted(bad_values)}', | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from fontbakery.prelude import FAIL, Message, check | ||
|
||
|
||
@check( | ||
id="arabic_spacing_symbols", | ||
proposal=[ | ||
"https://github.com/googlefonts/fontbakery/issues/4295", | ||
], | ||
rationale=""" | ||
Unicode has a few spacing symbols representing Arabic dots and other marks, | ||
but they are purposefully not classified as marks. | ||
Many fonts mistakenly classify them as marks, making them unsuitable | ||
for their original purpose as stand-alone symbols to used in pedagogical | ||
contexts discussing Arabic consonantal marks. | ||
""", | ||
severity=4, | ||
) | ||
def check_arabic_spacing_symbols(ttFont): | ||
"""Check that Arabic spacing symbols U+FBB2–FBC1 aren't classified as marks.""" | ||
|
||
# code-points | ||
ARABIC_SPACING_SYMBOLS = { | ||
0xFBB2, # Dot Above | ||
0xFBB3, # Dot Below | ||
0xFBB4, # Two Dots Above | ||
0xFBB5, # Two Dots Below | ||
0xFBB6, # Three Dots Above | ||
0xFBB7, # Three Dots Below | ||
0xFBB8, # Three Dots Pointing Downwards Above | ||
0xFBB9, # Three Dots Pointing Downwards Below | ||
0xFBBA, # Four Dots Above | ||
0xFBBB, # Four Dots Below | ||
0xFBBC, # Double Vertical Bar Below | ||
0xFBBD, # Two Dots Vertically Above | ||
0xFBBE, # Two Dots Vertically Below | ||
0xFBBF, # Ring | ||
0xFBC0, # Small Tah Above | ||
0xFBC1, # Small Tah Below | ||
0xFBC2, # Wasla Above | ||
} | ||
|
||
if "GDEF" in ttFont and ttFont["GDEF"].table.GlyphClassDef: | ||
class_def = ttFont["GDEF"].table.GlyphClassDef.classDefs | ||
reverseCmap = ttFont["cmap"].buildReversed() | ||
for name in reverseCmap: | ||
if reverseCmap[name].intersection(ARABIC_SPACING_SYMBOLS): | ||
if name in class_def and class_def[name] == 3: | ||
yield FAIL, Message( | ||
"mark-in-gdef", | ||
f'"{name}" is defined in GDEF as a mark (class 3).', | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from fontTools.pens.boundsPen import BoundsPen | ||
from fontbakery.prelude import check, Message, PASS, WARN, SKIP | ||
|
||
|
||
@check( | ||
id="caps_vertically_centered", | ||
rationale=""" | ||
This check suggests one possible approach to designing vertical metrics, | ||
but can be ingnored if you follow a different approach. | ||
In order to center text in buttons, lists, and grid systems | ||
with minimal additional CSS work, the uppercase glyphs should be | ||
vertically centered in the em box. | ||
This check mainly applies to Latin, Greek, Cyrillic, and other similar scripts. | ||
For non-latin scripts like Arabic, this check might not be applicable. | ||
There is a detailed description of this subject at: | ||
https://x.com/romanshamin_en/status/1562801657691672576 | ||
""", | ||
proposal="https://github.com/fonttools/fontbakery/issues/4139", | ||
) | ||
def check_caps_vertically_centered(ttFont): | ||
"""Check if uppercase glyphs are vertically centered.""" | ||
|
||
from copy import deepcopy | ||
|
||
ttFont_copy = deepcopy(ttFont) | ||
|
||
SOME_UPPERCASE_GLYPHS = ["A", "B", "C", "D", "E", "H", "I", "M", "O", "S", "T", "X"] | ||
glyphSet = ttFont_copy.getGlyphSet() | ||
|
||
for glyphname in SOME_UPPERCASE_GLYPHS: | ||
if glyphname not in glyphSet.keys(): | ||
yield SKIP, Message( | ||
"lacks-ascii", | ||
"The implementation of this check relies on a few samples" | ||
" of uppercase latin characters that are not available in this font.", | ||
) | ||
return | ||
|
||
highest_point_list = [] | ||
lowest_point_list = [] | ||
for glyphName in SOME_UPPERCASE_GLYPHS: | ||
pen = BoundsPen(glyphSet) | ||
glyphSet[glyphName].draw(pen) | ||
_, lowest_point, _, highest_point = pen.bounds | ||
highest_point_list.append(highest_point) | ||
lowest_point_list.append(lowest_point) | ||
|
||
upm = ttFont_copy["head"].unitsPerEm | ||
line_spacing_factor = 1.20 | ||
error_margin = (line_spacing_factor * upm) * 0.18 | ||
average_cap_height = sum(highest_point_list) / len(highest_point_list) | ||
average_descender = sum(lowest_point_list) / len(lowest_point_list) | ||
|
||
top_margin = ttFont["hhea"].ascent - average_cap_height | ||
bottom_margin = abs(ttFont["hhea"].descent) + average_descender | ||
|
||
difference = abs(top_margin - bottom_margin) | ||
|
||
if difference > error_margin: | ||
yield WARN, Message( | ||
"vertical-metrics-not-centered", | ||
"Uppercase glyphs are not vertically centered in the em box.", | ||
) | ||
else: | ||
yield PASS, "Uppercase glyphs are vertically centered in the em box." |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.