Esempio n. 1
0
def com_google_fonts_check_046(ttFont):
    """Font contains the first few mandatory glyphs (.null or NULL, CR and
  space)?"""
    from fontbakery.utils import get_glyph_name

    # It would be good to also check
    # for .notdef (codepoint = unspecified)
    null = get_glyph_name(ttFont, 0x0000)
    CR = get_glyph_name(ttFont, 0x000D)
    space = get_glyph_name(ttFont, 0x0020)

    missing = []
    if null is None:
        missing.append("0x0000")
    if CR is None:
        missing.append("0x000D")
    if space is None:
        missing.append("0x0020")
    if missing != []:
        yield WARN, ("Font is missing glyphs for"
                     " the following mandatory codepoints:"
                     " {}.").format(", ".join(missing))
    else:
        yield PASS, ("Font contains the first few mandatory glyphs"
                     " (.null or NULL, CR and space).")
Esempio n. 2
0
def com_google_fonts_check_046(ttFont):
  """Font contains the first few mandatory glyphs (.null or NULL, CR and
  space)?"""
  from fontbakery.utils import get_glyph_name

  # It would be good to also check
  # for .notdef (codepoint = unspecified)
  null = get_glyph_name(ttFont, 0x0000)
  CR = get_glyph_name(ttFont, 0x000D)
  space = get_glyph_name(ttFont, 0x0020)

  missing = []
  if null is None:
    missing.append("0x0000")
  if CR is None:
    missing.append("0x000D")
  if space is None:
    missing.append("0x0020")
  if missing != []:
    yield WARN, ("Font is missing glyphs for"
                 " the following mandatory codepoints:"
                 " {}.").format(", ".join(missing))
  else:
    yield PASS, ("Font contains the first few mandatory glyphs"
                 " (.null or NULL, CR and space).")
Esempio n. 3
0
def com_google_fonts_check_whitespace_widths(ttFont):
    """Space and non-breaking space have the same width?"""
    from fontbakery.utils import get_glyph_name

    space_name = get_glyph_name(ttFont, 0x0020)
    nbsp_name = get_glyph_name(ttFont, 0x00A0)

    space_width = ttFont['hmtx'][space_name][0]
    nbsp_width = ttFont['hmtx'][nbsp_name][0]

    if space_width > 0 and space_width == nbsp_width:
        yield PASS, "Space and non-breaking space have the same width."
    else:
        yield FAIL,\
              Message("different-widths",
                      f"Space and non-breaking space have differing width:"
                      f" The space glyph named {space_name}"
                      f" is {space_width} font units wide,"
                      f" non-breaking space named ({nbsp_name})"
                      f" is {nbsp_width} font units wide, and"
                      f" both should be positive and the same."
                      f" GlyphsApp has \"Sidebearing arithmetic\""
                      f" (https://glyphsapp.com/tutorials/spacing)"
                      f" which allows you to set the non-breaking"
                      f" space width to always equal the space width.")
def missing_whitespace_chars(ttFont):
    from fontbakery.utils import get_glyph_name
    space = get_glyph_name(ttFont, 0x0020)
    nbsp = get_glyph_name(ttFont, 0x00A0)
    # tab = get_glyph_name(ttFont, 0x0009)

    missing = []
    if space is None: missing.append("0x0020")
    if nbsp is None: missing.append("0x00A0")
    # fonts probably don't need an actual tab char
    # if tab is None: missing.append("0x0009")
    return missing
def missing_whitespace_chars(ttFont):
  from fontbakery.utils import get_glyph_name
  space = get_glyph_name(ttFont, 0x0020)
  nbsp = get_glyph_name(ttFont, 0x00A0)
  # tab = get_glyph_name(ttFont, 0x0009)

  missing = []
  if space is None: missing.append("0x0020")
  if nbsp is None: missing.append("0x00A0")
  # fonts probably don't need an actual tab char
  # if tab is None: missing.append("0x0009")
  return missing
Esempio n. 6
0
def com_google_fonts_check_whitespace_ink(ttFont):
    """Whitespace glyphs have ink?"""
    from fontbakery.utils import (get_glyph_name, glyph_has_ink)

    # This checks that certain glyphs are empty.
    # Some, but not all, are Unicode whitespace.

    # code-points for all Unicode whitespace chars
    # (according to Unicode 11.0 property list):
    WHITESPACE_CHARACTERS = {
        0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0x1680,
        0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
        0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000
    }

    # Code-points that do not have whitespace property, but
    # should not have a drawing.
    EXTRA_NON_DRAWING = {0x180E, 0x200B, 0x2060, 0xFEFF}

    # Make the set of non drawing characters.
    # OGHAM SPACE MARK U+1680 is removed as it is
    # a whitespace that should have a drawing.
    NON_DRAWING = WHITESPACE_CHARACTERS | EXTRA_NON_DRAWING - {0x1680}

    passed = True
    for codepoint in sorted(NON_DRAWING):
        g = get_glyph_name(ttFont, codepoint)
        if g is not None and glyph_has_ink(ttFont, g):
            passed = False
            yield FAIL,\
                  Message('has-ink',
                          f'Glyph "{g}" has ink.'
                          f' It needs to be replaced by an empty glyph.')
    if passed:
        yield PASS, "There is no whitespace glyph with ink."
Esempio n. 7
0
def com_google_fonts_check_050(ttFont):
    """Whitespace and non-breaking space have the same width?"""
    from fontbakery.utils import get_glyph_name

    space_name = get_glyph_name(ttFont, 0x0020)
    nbsp_name = get_glyph_name(ttFont, 0x00A0)

    space_width = ttFont['hmtx'][space_name][0]
    nbsp_width = ttFont['hmtx'][nbsp_name][0]

    if space_width > 0 and space_width == nbsp_width:
        yield PASS, "Whitespace and non-breaking space have the same width."
    else:
        yield FAIL, (
            "Whitespace and non-breaking space have differing width:"
            " Whitespace ({}) is {} font units wide, non-breaking space"
            " ({}) is {} font units wide. Both should be positive and the"
            " same.").format(space_name, space_width, nbsp_name, nbsp_width)
Esempio n. 8
0
def com_google_fonts_check_whitespace_widths(ttFont):
  """Whitespace and non-breaking space have the same width?"""
  from fontbakery.utils import get_glyph_name

  space_name = get_glyph_name(ttFont, 0x0020)
  nbsp_name = get_glyph_name(ttFont, 0x00A0)

  space_width = ttFont['hmtx'][space_name][0]
  nbsp_width = ttFont['hmtx'][nbsp_name][0]

  if space_width > 0 and space_width == nbsp_width:
    yield PASS, "Whitespace and non-breaking space have the same width."
  else:
    yield FAIL, ("Whitespace and non-breaking space have differing width:"
                 " Whitespace ({}) is {} font units wide, non-breaking space"
                 " ({}) is {} font units wide. Both should be positive and the"
                 " same.").format(space_name, space_width, nbsp_name,
                                  nbsp_width)
Esempio n. 9
0
def com_google_fonts_check_048(ttFont):
    """Font has **proper** whitespace glyph names?"""
    from fontbakery.utils import get_glyph_name

    def getGlyphEncodings(font, names):
        result = set()
        for subtable in font['cmap'].tables:
            if subtable.isUnicode():
                for codepoint, name in subtable.cmap.items():
                    if name in names:
                        result.add(codepoint)
        return result

    if ttFont['post'].formatType == 3.0:
        yield SKIP, "Font has version 3 post table."
    else:
        failed = False
        space_enc = getGlyphEncodings(ttFont, ["uni0020", "space"])
        nbsp_enc = getGlyphEncodings(
            ttFont, ["uni00A0", "nonbreakingspace", "nbspace", "nbsp"])
        space = get_glyph_name(ttFont, 0x0020)
        if 0x0020 not in space_enc:
            failed = True
            yield FAIL, Message("bad20", ("Glyph 0x0020 is called \"{}\":"
                                          " Change to \"space\""
                                          " or \"uni0020\"").format(space))

        nbsp = get_glyph_name(ttFont, 0x00A0)
        if 0x00A0 not in nbsp_enc:
            if 0x00A0 in space_enc:
                # This is OK.
                # Some fonts use the same glyph for both space and nbsp.
                pass
            else:
                failed = True
                yield FAIL, Message("badA0", ("Glyph 0x00A0 is called \"{}\":"
                                              " Change to \"nbsp\""
                                              " or \"uni00A0\"").format(nbsp))

        if failed is False:
            yield PASS, "Font has **proper** whitespace glyph names."
Esempio n. 10
0
def com_google_fonts_check_048(ttFont):
  """Font has **proper** whitespace glyph names?"""
  from fontbakery.utils import get_glyph_name

  def getGlyphEncodings(font, names):
    result = set()
    for subtable in font['cmap'].tables:
      if subtable.isUnicode():
        for codepoint, name in subtable.cmap.items():
          if name in names:
            result.add(codepoint)
    return result

  if ttFont['post'].formatType == 3.0:
    yield SKIP, "Font has version 3 post table."
  else:
    failed = False
    space_enc = getGlyphEncodings(ttFont, ["uni0020", "space"])
    nbsp_enc = getGlyphEncodings(
        ttFont, ["uni00A0", "nonbreakingspace", "nbspace", "nbsp"])
    space = get_glyph_name(ttFont, 0x0020)
    if 0x0020 not in space_enc:
      failed = True
      yield FAIL, Message("bad20", ("Glyph 0x0020 is called \"{}\":"
                                    " Change to \"space\""
                                    " or \"uni0020\"").format(space))

    nbsp = get_glyph_name(ttFont, 0x00A0)
    if 0x00A0 not in nbsp_enc:
      if 0x00A0 in space_enc:
        # This is OK.
        # Some fonts use the same glyph for both space and nbsp.
        pass
      else:
        failed = True
        yield FAIL, Message("badA0", ("Glyph 0x00A0 is called \"{}\":"
                                      " Change to \"nbsp\""
                                      " or \"uni00A0\"").format(nbsp))

    if failed is False:
      yield PASS, "Font has **proper** whitespace glyph names."
Esempio n. 11
0
def com_google_fonts_check_whitespace_widths(ttFont):
    """Whitespace and non-breaking space have the same width?"""
    from fontbakery.utils import get_glyph_name

    space_name = get_glyph_name(ttFont, 0x0020)
    nbsp_name = get_glyph_name(ttFont, 0x00A0)

    space_width = ttFont['hmtx'][space_name][0]
    nbsp_width = ttFont['hmtx'][nbsp_name][0]

    if space_width > 0 and space_width == nbsp_width:
        yield PASS, "Whitespace and non-breaking space have the same width."
    else:
        yield FAIL,\
              Message("different-widths",
                      f"Whitespace and non-breaking space have differing width:"
                      f" Whitespace ({space_name})"
                      f" is {space_width} font units wide,"
                      f" non-breaking space ({nbsp_name})"
                      f" is {nbsp_width} font units wide."
                      f" Both should be positive and the same.")
Esempio n. 12
0
def com_google_fonts_check_049(ttFont):
    """Whitespace glyphs have ink?"""
    from fontbakery.utils import get_glyph_name

    def glyphHasInk(font, name):
        """Checks if specified glyph has any ink.

    That is, that it has at least one defined contour associated.
    Composites are considered to have ink if any of their components have ink.
    Args:
        font:       the font
        glyph_name: The name of the glyph to check for ink.
    Returns:
        True if the font has at least one contour associated with it.
    """
        glyph = font['glyf'].glyphs[name]
        glyph.expand(font['glyf'])
        if not glyph.isComposite():
            if glyph.numberOfContours == 0:
                return False
            (coords, _, _) = glyph.getCoordinates(font['glyf'])
            # you need at least 3 points to draw
            return len(coords) > 2

        # composite is blank if composed of blanks
        # if you setup a font with cycles you are just a bad person
        # Dave: lol, bad people exist, so put a recursion in this recursion
        for glyph_name in glyph.getComponentNames(glyph.components):
            if glyphHasInk(font, glyph_name):
                return True
        return False

    # code-points for all "whitespace" chars:
    WHITESPACE_CHARACTERS = [
        0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0x1680,
        0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
        0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0x180E, 0x200B,
        0x2060, 0xFEFF
    ]
    failed = False
    for codepoint in WHITESPACE_CHARACTERS:
        g = get_glyph_name(ttFont, codepoint)
        if g is not None and glyphHasInk(ttFont, g):
            failed = True
            yield FAIL, ("Glyph \"{}\" has ink."
                         " It needs to be replaced by"
                         " an empty glyph.").format(g)
    if not failed:
        yield PASS, "There is no whitespace glyph with ink."
Esempio n. 13
0
def com_google_fonts_check_049(ttFont):
  """Whitespace glyphs have ink?"""
  from fontbakery.utils import get_glyph_name

  def glyphHasInk(font, name):
    """Checks if specified glyph has any ink.

    That is, that it has at least one defined contour associated.
    Composites are considered to have ink if any of their components have ink.
    Args:
        font:       the font
        glyph_name: The name of the glyph to check for ink.
    Returns:
        True if the font has at least one contour associated with it.
    """
    glyph = font['glyf'].glyphs[name]
    glyph.expand(font['glyf'])
    if not glyph.isComposite():
      if glyph.numberOfContours == 0:
        return False
      (coords, _, _) = glyph.getCoordinates(font['glyf'])
      # you need at least 3 points to draw
      return len(coords) > 2

    # composite is blank if composed of blanks
    # if you setup a font with cycles you are just a bad person
    # Dave: lol, bad people exist, so put a recursion in this recursion
    for glyph_name in glyph.getComponentNames(glyph.components):
      if glyphHasInk(font, glyph_name):
        return True
    return False

  # code-points for all "whitespace" chars:
  WHITESPACE_CHARACTERS = [
      0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0x1680,
      0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
      0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0x180E, 0x200B,
      0x2060, 0xFEFF
  ]
  failed = False
  for codepoint in WHITESPACE_CHARACTERS:
    g = get_glyph_name(ttFont, codepoint)
    if g is not None and glyphHasInk(ttFont, g):
      failed = True
      yield FAIL, ("Glyph \"{}\" has ink."
                   " It needs to be replaced by"
                   " an empty glyph.").format(g)
  if not failed:
    yield PASS, "There is no whitespace glyph with ink."
Esempio n. 14
0
def com_google_fonts_check_049(ttFont):
    """Whitespace glyphs have ink?"""
    from fontbakery.utils import get_glyph_name, glyph_has_ink

    # code-points for all "whitespace" chars:
    WHITESPACE_CHARACTERS = [
        0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0x1680,
        0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
        0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0x180E, 0x200B,
        0x2060, 0xFEFF
    ]
    failed = False
    for codepoint in WHITESPACE_CHARACTERS:
        g = get_glyph_name(ttFont, codepoint)
        if g is not None and glyph_has_ink(ttFont, g):
            failed = True
            yield FAIL, ("Glyph \"{}\" has ink."
                         " It needs to be replaced by"
                         " an empty glyph.").format(g)
    if not failed:
        yield PASS, "There is no whitespace glyph with ink."
Esempio n. 15
0
def com_google_fonts_check_whitespace_ink(ttFont):
  """Whitespace glyphs have ink?"""
  from fontbakery.utils import get_glyph_name, glyph_has_ink

  # code-points for all "whitespace" chars:
  WHITESPACE_CHARACTERS = [
      0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0x1680,
      0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
      0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0x180E, 0x200B,
      0x2060, 0xFEFF
  ]
  failed = False
  for codepoint in WHITESPACE_CHARACTERS:
    g = get_glyph_name(ttFont, codepoint)
    if g is not None and glyph_has_ink(ttFont, g):
      failed = True
      yield FAIL, ("Glyph \"{}\" has ink."
                   " It needs to be replaced by"
                   " an empty glyph.").format(g)
  if not failed:
    yield PASS, "There is no whitespace glyph with ink."
Esempio n. 16
0
def com_google_fonts_check_whitespace_glyphnames(ttFont):
    """Font has **proper** whitespace glyph names?"""
    from fontbakery.utils import get_glyph_name

    # AGL recommended names, according to Adobe Glyph List for new fonts:
    AGL_RECOMMENDED_0020 = {'space'}
    AGL_RECOMMENDED_00A0 = {"uni00A0", "space"}  # "space" is in this set because some fonts
                                                 # use the same glyph for U+0020 and U+00A0
                                                 # Including it here also removes a warning
                                                 # when U+0020 is wrong, but U+00A0 is okay.

    # AGL compliant names, but not recommended for new fonts:
    AGL_COMPLIANT_BUT_NOT_RECOMMENDED_0020 = {'uni0020',
                                              'u0020',
                                              'u00020',
                                              'u000020'}
    AGL_COMPLIANT_BUT_NOT_RECOMMENDED_00A0 = {'nonbreakingspace',
                                              'nbspace',
                                              'u00A0',
                                              'u000A0',
                                              'u0000A0'}

    if ttFont['post'].formatType == 3.0:
        yield SKIP, "Font has version 3 post table."
    else:
        passed = True

        space = get_glyph_name(ttFont, 0x0020)
        if not space:
            passed = False
            yield FAIL,\
                  Message('missing-0020',
                          'Glyph 0x0020 is missing a glyph name!')

        elif space in AGL_RECOMMENDED_0020:
            pass

        elif space in AGL_COMPLIANT_BUT_NOT_RECOMMENDED_0020:
            passed = False
            yield WARN,\
                  Message('not-recommended-0020',
                          f'Glyph 0x0020 is called "{space}":'
                          f' Change to "space"')
        else:
            passed = False
            yield FAIL,\
                  Message('non-compliant-0020',
                          f'Glyph 0x0020 is called "{space}":'
                          f' Change to "space"')


        nbsp = get_glyph_name(ttFont, 0x00A0)
        if not nbsp:
            yield FAIL,\
                  Message('missing-00a0',
                          'Glyph 0x00A0 is missing a glyph name!')

        elif nbsp == space:
            # This is OK.
            # Some fonts use the same glyph for both space and nbsp.
            pass

        elif nbsp in AGL_RECOMMENDED_00A0:
            pass

        elif nbsp in AGL_COMPLIANT_BUT_NOT_RECOMMENDED_00A0:
            passed = False
            yield WARN,\
                  Message('not-recommended-00a0',
                          f'Glyph 0x00A0 is called "{nbsp}":'
                          f' Change to "uni00A0"')
        else:
            passed = False
            yield FAIL,\
                  Message('non-compliant-00a0',
                          f'Glyph 0x00A0 is called "{nbsp}":'
                          f' Change to "uni00A0"')

        if passed:
            yield PASS, "Font has **AGL recommended** names for whitespace glyphs."