def com_google_fonts_check_name_match_familyname_fullfont(ttFont): """Does full font name begin with the font family name?""" from fontbakery.utils import get_name_entry_strings familyname = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) fullfontname = get_name_entry_strings(ttFont, NameID.FULL_FONT_NAME) if len(familyname) == 0: yield FAIL,\ Message("no-font-family-name", "Font lacks a NameID.FONT_FAMILY_NAME" " entry in the 'name' table.") elif len(fullfontname) == 0: yield FAIL,\ Message("no-full-font-name", "Font lacks a NameID.FULL_FONT_NAME" " entry in the 'name' table.") else: # we probably should check all found values are equivalent. # and, in that case, then performing the rest of the check # with only the first occurences of the name entries # will suffice: fullfontname = fullfontname[0] familyname = familyname[0] if not fullfontname.startswith(familyname): yield FAIL,\ Message("does-not", f"On the 'name' table, the full font name" f" (NameID {NameID.FULL_FONT_NAME}" f" - FULL_FONT_NAME: '{familyname}')" f" does not begin with font family name" f" (NameID {NameID.FONT_FAMILY_NAME}" f" - FONT_FAMILY_NAME: '{fullfontname}')") else: yield PASS, "Full font name begins with the font family name."
def com_google_fonts_check_068(ttFont): """Does full font name begin with the font family name?""" from fontbakery.utils import get_name_entry_strings from fontbakery.constants import (NAMEID_FONT_FAMILY_NAME, NAMEID_FULL_FONT_NAME) familyname = get_name_entry_strings(ttFont, NAMEID_FONT_FAMILY_NAME) fullfontname = get_name_entry_strings(ttFont, NAMEID_FULL_FONT_NAME) if len(familyname) == 0: yield FAIL, Message("no-font-family-name", ("Font lacks a NAMEID_FONT_FAMILY_NAME" " entry in the 'name' table.")) elif len(fullfontname) == 0: yield FAIL, Message("no-full-font-name", ("Font lacks a NAMEID_FULL_FONT_NAME" " entry in the 'name' table.")) else: # we probably should check all found values are equivalent. # and, in that case, then performing the rest of the check # with only the first occurences of the name entries # will suffice: fullfontname = fullfontname[0] familyname = familyname[0] if not fullfontname.startswith(familyname): yield FAIL, Message( "does-not", (" On the 'name' table, the full font name" " (NameID {} - FULL_FONT_NAME: '{}')" " does not begin with font family name" " (NameID {} - FONT_FAMILY_NAME:" " '{}')".format(NAMEID_FULL_FONT_NAME, familyname, NAMEID_FONT_FAMILY_NAME, fullfontname))) else: yield PASS, "Full font name begins with the font family name."
def com_adobe_fonts_check_family_max_4_fonts_per_family_name(ttFonts): """Verify that each group of fonts with the same nameID 1 has maximum of 4 fonts""" from collections import Counter from fontbakery.utils import get_name_entry_strings failed = False family_names = list() for ttFont in ttFonts: names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) # names_list will likely contain multiple entries, e.g. multiple copies # of the same name in the same language for different platforms, but # also different names in different languages, we use set() below # to remove the duplicates and only store the unique family name(s) # used for a given font names_set = set(names_list) family_names.extend(names_set) counter = Counter(family_names) for family_name, count in counter.items(): if count > 4: failed = True yield FAIL, ( "Family '{}' has {} fonts (should be 4 or fewer).").format( family_name, count) if not failed: yield PASS, ("There were no more than 4 fonts per family name.")
def com_adobe_fonts_check_family_max_4_fonts_per_family_name(ttFonts): """Verify that each group of fonts with the same nameID 1 has maximum of 4 fonts""" from collections import Counter from fontbakery.utils import get_name_entry_strings failed = False family_names = list() for ttFont in ttFonts: names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) # names_list will likely contain multiple entries, e.g. multiple copies # of the same name in the same language for different platforms, but # also different names in different languages, we use set() below # to remove the duplicates and only store the unique family name(s) # used for a given font names_set = set(names_list) family_names.extend(names_set) counter = Counter(family_names) for family_name, count in counter.items(): if count > 4: failed = True yield FAIL, ("Family '{}' has {} fonts (should be 4 or fewer)." ).format(family_name, count) if not failed: yield PASS, ("There were no more than 4 fonts per family name.")
def com_adobe_fonts_check_family_max_4_fonts_per_family_name(ttFonts): """Verify that each group of fonts with the same nameID 1 has maximum of 4 fonts""" from collections import Counter from fontbakery.utils import get_name_entry_strings family_names = list() for ttFont in ttFonts: names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME, PlatformID.WINDOWS, WindowsEncodingID.UNICODE_BMP, WindowsLanguageID.ENGLISH_USA) # names_list may contain multiple entries. # We use set() below to remove the duplicates and only store # the unique family name(s) used for a given font names_set = set(names_list) family_names.extend(names_set) passed = True counter = Counter(family_names) for family_name, count in counter.items(): if count > 4: passed = False yield FAIL,\ Message("too-many", f"Family '{family_name}' has {count} fonts" f" (should be 4 or fewer).") if passed: yield PASS, ("There were no more than 4 fonts per family name.")
def variable_font_filename(ttFont): from fontbakery.utils import get_name_entry_strings from fontbakery.constants import (MacStyle, NameID) familynames = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) typo_familynames = get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_FAMILY_NAME) if familynames == []: return None familyname = typo_familynames[0] if typo_familynames else familynames[0] familyname = "".join(familyname.split(' ')) #remove spaces if bool(ttFont["head"].macStyle & MacStyle.ITALIC): familyname += "-Italic" tags = ttFont["fvar"].axes tags = list(map(lambda t: t.axisTag, tags)) tags.sort() tags = "[{}]".format(",".join(tags)) return f"{familyname}{tags}.ttf"
def com_adobe_fonts_check_family_bold_italic_unique_for_nameid1(RIBBI_ttFonts): """Check that OS/2.fsSelection bold & italic settings are unique for each NameID1""" from collections import Counter from fontbakery.utils import get_name_entry_strings from fontbakery.constants import NameID, FsSelection failed = False family_name_and_bold_italic = list() for ttFont in RIBBI_ttFonts: names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) # names_list will likely contain multiple entries, e.g. multiple copies # of the same name in the same language for different platforms, but # also different names in different languages, we use set() below # to remove the duplicates and only store the unique family name(s) # used for a given font names_set = set(names_list) bold = (ttFont['OS/2'].fsSelection & FsSelection.BOLD) != 0 italic = (ttFont['OS/2'].fsSelection & FsSelection.ITALIC) != 0 bold_italic = 'Bold=%r, Italic=%r' % (bold, italic) for name in names_set: family_name_and_bold_italic.append(( name, bold_italic, )) counter = Counter(family_name_and_bold_italic) for (family_name, bold_italic), count in counter.items(): if count > 1: failed = True yield FAIL, \ Message("unique-fsselection", f"Family '{family_name}' has {count} fonts" f" (should be no more than 1) with the" f" same OS/2.fsSelection bold & italic settings:" f" {bold_italic}") if not failed: yield PASS, ("The OS/2.fsSelection bold & italic settings were unique " "within each compatible family group.")
def test_font_psnames(): root = etree.parse(str(_noto_4_android_file())) errors = [] font_to_xml_psnames = collections.defaultdict(set) for font_el in root.xpath("//font[@path]"): path = _font_path(font_el) psname = _psname(font_el) font_to_xml_psnames[(path, font_el.attrib.get("index", -1))].add(str(psname)) for (font_path, font_number), xml_psnames in font_to_xml_psnames.items(): font = _open_font_path(font_path, font_number) postscript_names = set(get_name_entry_strings(font, _POSTSCRIPT_NAME)) if len(postscript_names) != 1: errors.append(f"font file {font_path} should have a single postScriptName and not {postscript_names}") continue for xml_psname in xml_psnames: if not (xml_psname in postscript_names): errors.append(f"postScriptName=\"{postscript_names[0]}\" in font file {font_path} doesn't match the entry in XML: {xml_psname}") assert not errors, ", ".join(errors)
def org_sil_software_version_format(ttFont): "Version format is correct in 'name' table?" from fontbakery.utils import get_name_entry_strings import re def is_valid_version_format(value): return re.match(r'Version [0-9]+\.\d{3}( .+)*$', value) failed = False warned = False version_entries = get_name_entry_strings(ttFont, NameID.VERSION_STRING) if len(version_entries) == 0: failed = True yield FAIL,\ Message("no-version-string", f"Font lacks a NameID.VERSION_STRING" f" (nameID={NameID.VERSION_STRING}) entry") for ventry in version_entries: if not re.match(r'Version [0-9]+\.\d{3}( .+)*$', ventry): failed = True yield FAIL,\ Message("bad-version-strings", f'The NameID.VERSION_STRING' f' (nameID={NameID.VERSION_STRING}) value must' f' follow the pattern "Version X.nnn devstring" with X.nnn' f' greater than or equal to 0.000.' f' Current version string is: "{ventry}"') elif not re.match(r'Version [1-9][0-9]*\.\d{3}$', ventry): warned = True yield WARN, \ Message("nonproduction-version-strings", f'For production fonts, the NameID.VERSION_STRING' f' (nameID={NameID.VERSION_STRING}) value must' f' follow the pattern "Version X.nnn" with X.nnn' f' greater than or equal to 1.000.' f' Current version string is: "{ventry}"') if not failed and not warned: yield PASS, "Version format in NAME table entries is correct."
def com_google_fonts_check_163(ttFont): """Combined length of family and style must not exceed 20 characters.""" from unidecode import unidecode from fontbakery.utils import (get_name_entries, get_name_entry_strings) from fontbakery.constants import (NAMEID_FONT_FAMILY_NAME, NAMEID_FONT_SUBFAMILY_NAME, PLATID_STR) failed = False for familyname in get_name_entries(ttFont, NAMEID_FONT_FAMILY_NAME): # we'll only match family/style name entries with the same platform ID: plat = familyname.platformID familyname_str = familyname.string.decode(familyname.getEncoding()) for stylename_str in get_name_entry_strings( ttFont, NAMEID_FONT_SUBFAMILY_NAME, platformID=plat): if len(familyname_str + stylename_str) > 20: failed = True yield WARN, ("The combined length of family and style" " exceeds 20 chars in the following '{}' entries:" " FONT_FAMILY_NAME = '{}' / SUBFAMILY_NAME = '{}'" "").format(PLATID_STR[plat], unidecode(familyname_str), unidecode(stylename_str)) if not failed: yield PASS, "All name entries are good."
def com_google_fonts_check_163(ttFont): """Combined length of family and style must not exceed 20 characters.""" from unidecode import unidecode from fontbakery.utils import (get_name_entries, get_name_entry_strings) failed = False for familyname in get_name_entries(ttFont, NameID.FONT_FAMILY_NAME): # we'll only match family/style name entries with the same platform ID: plat = familyname.platformID familyname_str = familyname.string.decode(familyname.getEncoding()) for stylename_str in get_name_entry_strings(ttFont, NameID.FONT_SUBFAMILY_NAME, platformID=plat): if len(familyname_str + stylename_str) > 20: failed = True yield WARN, ("The combined length of family and style" " exceeds 20 chars in the following '{}' entries:" " FONT_FAMILY_NAME = '{}' / SUBFAMILY_NAME = '{}'" "").format( PlatformID(plat).name, unidecode(familyname_str), unidecode(stylename_str)) if not failed: yield PASS, "All name entries are good."
def com_adobe_fonts_check_family_bold_italic_unique_for_nameid1(ttFonts): """Check that OS/2.fsSelection bold & italic settings are unique for each NameID1""" from collections import Counter from fontbakery.utils import get_name_entry_strings from fontbakery.constants import NameID, FsSelection failed = False family_name_and_bold_italic = list() for ttFont in ttFonts: names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME) # names_list will likely contain multiple entries, e.g. multiple copies # of the same name in the same language for different platforms, but # also different names in different languages, we use set() below # to remove the duplicates and only store the unique family name(s) # used for a given font names_set = set(names_list) bold = (ttFont['OS/2'].fsSelection & FsSelection.BOLD) != 0 italic = (ttFont['OS/2'].fsSelection & FsSelection.ITALIC) != 0 bold_italic = 'Bold=%r, Italic=%r' % (bold, italic) for name in names_set: family_name_and_bold_italic.append((name, bold_italic,)) counter = Counter(family_name_and_bold_italic) for (family_name, bold_italic), count in counter.items(): if count > 1: failed = True yield FAIL, ("Family '{}' has {} fonts (should be no more than 1) with " "the same OS/2.fsSelection bold & italic settings: {}" ).format(family_name, count, bold_italic) if not failed: yield PASS, ("The OS/2.fsSelection bold & italic settings were unique " "within each compatible family group.")
def com_google_fonts_check_071(ttFont): """Font follows the family naming recommendations?""" # See http://forum.fontlab.com/index.php?topic=313.0 import re from fontbakery.utils import get_name_entry_strings from fontbakery.constants import ( NAMEID_POSTSCRIPT_NAME, NAMEID_FULL_FONT_NAME, NAMEID_FONT_FAMILY_NAME, NAMEID_FONT_SUBFAMILY_NAME, NAMEID_TYPOGRAPHIC_FAMILY_NAME, NAMEID_TYPOGRAPHIC_SUBFAMILY_NAME) bad_entries = [] # <Postscript name> may contain only a-zA-Z0-9 # and one hyphen bad_psname = re.compile("[^A-Za-z0-9-]") for string in get_name_entry_strings(ttFont, NAMEID_POSTSCRIPT_NAME): if bad_psname.search(string): bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'May contain only a-zA-Z0-9' ' characters and an hyphen.' }) if string.count('-') > 1: bad_entries.append({ 'field': 'Postscript Name', 'value': string, 'rec': 'May contain not more' ' than a single hyphen' }) for string in get_name_entry_strings(ttFont, NAMEID_FULL_FONT_NAME): if len(string) >= 64: bad_entries.append({ 'field': 'Full Font Name', 'value': string, 'rec': 'exceeds max length (63)' }) for string in get_name_entry_strings(ttFont, NAMEID_POSTSCRIPT_NAME): if len(string) >= 30: bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'exceeds max length (29)' }) for string in get_name_entry_strings(ttFont, NAMEID_FONT_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_FONT_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_TYPOGRAPHIC_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_TYPOGRAPHIC_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) weight_value = None if "OS/2" in ttFont: field = "OS/2 usWeightClass" weight_value = ttFont["OS/2"].usWeightClass if weight_value is not None: # <Weight> value >= 250 and <= 900 in steps of 50 if weight_value % 50 != 0: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be a multiple of 50." }) full_info = " " " 'Having a weightclass of 100 or 200 can result in a \"smear bold\" or" " (unintentionally) returning the style-linked bold. Because of this," " you may wish to manually override the weightclass setting for all" " extra light, ultra light or thin fonts'" " - http://www.adobe.com/devnet/opentype/afdko/topic_font_wt_win.html" if weight_value < 250: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be 250 or more." + full_info }) if weight_value > 900: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be 900 or less." }) if len(bad_entries) > 0: table = "| Field | Value | Recommendation |\n" table += "|:----- |:----- |:-------------- |\n" for bad in bad_entries: table += "| {} | {} | {} |\n".format(bad["field"], bad["value"], bad["rec"]) yield INFO, ("Font does not follow " "some family naming recommendations:\n\n" "{}").format(table) else: yield PASS, "Font follows the family naming recommendations."
def com_google_fonts_check_family_naming_recommendations(ttFont): """Font follows the family naming recommendations?""" # See http://forum.fontlab.com/index.php?topic=313.0 import re from fontbakery.utils import get_name_entry_strings bad_entries = [] # <Postscript name> may contain only a-zA-Z0-9 # and one hyphen bad_psname = re.compile("[^A-Za-z0-9-]") for string in get_name_entry_strings(ttFont, NameID.POSTSCRIPT_NAME): if bad_psname.search(string): bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': ('May contain only a-zA-Z0-9' ' characters and an hyphen.') }) if string.count('-') > 1: bad_entries.append({ 'field': 'Postscript Name', 'value': string, 'rec': ('May contain not more' ' than a single hyphen') }) for string in get_name_entry_strings(ttFont, NameID.FULL_FONT_NAME): if len(string) >= 64: bad_entries.append({ 'field': 'Full Font Name', 'value': string, 'rec': 'exceeds max length (63)' }) for string in get_name_entry_strings(ttFont, NameID.POSTSCRIPT_NAME): if len(string) >= 30: bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'exceeds max length (29)' }) for string in get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.FONT_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) if len(bad_entries) > 0: table = "| Field | Value | Recommendation |\n" table += "|:----- |:----- |:-------------- |\n" for bad in bad_entries: table += "| {} | {} | {} |\n".format(bad["field"], bad["value"], bad["rec"]) yield INFO,\ Message("bad-entries", f"Font does not follow " f"some family naming recommendations:\n" f"\n" f"{table}") else: yield PASS, "Font follows the family naming recommendations."
def com_google_fonts_check_family_naming_recommendations(ttFont): """Font follows the family naming recommendations?""" # See http://forum.fontlab.com/index.php?topic=313.0 import re from fontbakery.utils import get_name_entry_strings bad_entries = [] # <Postscript name> may contain only a-zA-Z0-9 # and one hyphen bad_psname = re.compile("[^A-Za-z0-9-]") for string in get_name_entry_strings(ttFont, NameID.POSTSCRIPT_NAME): if bad_psname.search(string): bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': ('May contain only a-zA-Z0-9' ' characters and an hyphen.') }) if string.count('-') > 1: bad_entries.append({ 'field': 'Postscript Name', 'value': string, 'rec': ('May contain not more' ' than a single hyphen') }) for string in get_name_entry_strings(ttFont, NameID.FULL_FONT_NAME): if len(string) >= 64: bad_entries.append({ 'field': 'Full Font Name', 'value': string, 'rec': 'exceeds max length (63)' }) for string in get_name_entry_strings(ttFont, NameID.POSTSCRIPT_NAME): if len(string) >= 30: bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'exceeds max length (29)' }) for string in get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.FONT_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) if len(bad_entries) > 0: table = "| Field | Value | Recommendation |\n" table += "|:----- |:----- |:-------------- |\n" for bad in bad_entries: table += "| {} | {} | {} |\n".format(bad["field"], bad["value"], bad["rec"]) yield INFO, ("Font does not follow " "some family naming recommendations:\n\n" "{}").format(table) else: yield PASS, "Font follows the family naming recommendations."
def typographic_familynames(ttFont): from fontbakery.utils import get_name_entry_strings return get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_FAMILY_NAME)
def font_familynames(ttFont): from fontbakery.utils import get_name_entry_strings return get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME)
def com_google_fonts_check_071(ttFont): """Font follows the family naming recommendations?""" # See http://forum.fontlab.com/index.php?topic=313.0 import re from fontbakery.utils import get_name_entry_strings from fontbakery.constants import (NAMEID_POSTSCRIPT_NAME, NAMEID_FULL_FONT_NAME, NAMEID_FONT_FAMILY_NAME, NAMEID_FONT_SUBFAMILY_NAME, NAMEID_TYPOGRAPHIC_FAMILY_NAME, NAMEID_TYPOGRAPHIC_SUBFAMILY_NAME) bad_entries = [] # <Postscript name> may contain only a-zA-Z0-9 # and one hyphen bad_psname = re.compile("[^A-Za-z0-9-]") for string in get_name_entry_strings(ttFont, NAMEID_POSTSCRIPT_NAME): if bad_psname.search(string): bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'May contain only a-zA-Z0-9' ' characters and an hyphen.' }) if string.count('-') > 1: bad_entries.append({ 'field': 'Postscript Name', 'value': string, 'rec': 'May contain not more' ' than a single hyphen' }) for string in get_name_entry_strings(ttFont, NAMEID_FULL_FONT_NAME): if len(string) >= 64: bad_entries.append({ 'field': 'Full Font Name', 'value': string, 'rec': 'exceeds max length (63)' }) for string in get_name_entry_strings(ttFont, NAMEID_POSTSCRIPT_NAME): if len(string) >= 30: bad_entries.append({ 'field': 'PostScript Name', 'value': string, 'rec': 'exceeds max length (29)' }) for string in get_name_entry_strings(ttFont, NAMEID_FONT_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_FONT_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_TYPOGRAPHIC_FAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Family Name', 'value': string, 'rec': 'exceeds max length (31)' }) for string in get_name_entry_strings(ttFont, NAMEID_TYPOGRAPHIC_SUBFAMILY_NAME): if len(string) >= 32: bad_entries.append({ 'field': 'OT Style Name', 'value': string, 'rec': 'exceeds max length (31)' }) weight_value = None if "OS/2" in ttFont: field = "OS/2 usWeightClass" weight_value = ttFont["OS/2"].usWeightClass if weight_value is not None: # <Weight> value >= 250 and <= 900 in steps of 50 if weight_value % 50 != 0: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be a multiple of 50." }) full_info = " " " 'Having a weightclass of 100 or 200 can result in a \"smear bold\" or" " (unintentionally) returning the style-linked bold. Because of this," " you may wish to manually override the weightclass setting for all" " extra light, ultra light or thin fonts'" " - http://www.adobe.com/devnet/opentype/afdko/topic_font_wt_win.html" if weight_value < 250: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be 250 or more." + full_info }) if weight_value > 900: bad_entries.append({ "field": field, 'value': weight_value, "rec": "Value should ideally be 900 or less." }) if len(bad_entries) > 0: table = "| Field | Value | Recommendation |\n" table += "|:----- |:----- |:-------------- |\n" for bad in bad_entries: table += "| {} | {} | {} |\n".format(bad["field"], bad["value"], bad["rec"]) yield INFO, ("Font does not follow " "some family naming recommendations:\n\n" "{}").format(table) else: yield PASS, "Font follows the family naming recommendations."