Example #1
0
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."
Example #2
0
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."
Example #3
0
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.")
Example #4
0
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.")
Example #5
0
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.")
Example #6
0
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"
Example #7
0
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.")
Example #8
0
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)
Example #9
0
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."
Example #10
0
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."
Example #11
0
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."
Example #12
0
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.")
Example #13
0
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."
Example #14
0
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."
Example #15
0
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."
Example #16
0
def typographic_familynames(ttFont):
    from fontbakery.utils import get_name_entry_strings
    return get_name_entry_strings(ttFont, NameID.TYPOGRAPHIC_FAMILY_NAME)
Example #17
0
def font_familynames(ttFont):
    from fontbakery.utils import get_name_entry_strings
    return get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME)
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)
Example #20
0
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."