test_web.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from fontbakery.callable import check
  2. from fontbakery.callable import condition
  3. from fontbakery.checkrunner import Section, PASS, FAIL, WARN
  4. from fontbakery.fonts_profile import profile_factory
  5. from tests.test_general import (
  6. font_family,
  7. font_style,
  8. font_features,
  9. com_roboto_fonts_check_italic_angle,
  10. com_roboto_fonts_check_fs_type,
  11. com_roboto_fonts_check_vendorid,
  12. com_roboto_fonts_check_digit_widths,
  13. com_roboto_fonts_check_features,
  14. )
  15. from fontbakery.profiles.shared_conditions import is_italic
  16. @condition
  17. def include_features():
  18. return set([
  19. 'c2sc', 'ccmp', 'cpsp', 'dlig', 'dnom', 'frac', 'kern', 'liga', 'lnum',
  20. 'locl', 'numr', 'onum', 'pnum', 'smcp', 'ss01', 'ss02', 'ss03', 'ss04',
  21. 'ss05', 'ss06', 'ss07', 'tnum', 'sups', 'subs'])
  22. profile = profile_factory(default_section=Section("Roboto web v3"))
  23. ROBOTO_PROFILE_CHECKS = [
  24. "com.roboto.fonts/check/vertical_metrics",
  25. "com.roboto.fonts/check/oblique_bits_not_set",
  26. "com.roboto.fonts/check/unique_id",
  27. "com.roboto.fonts/check/hinting",
  28. "com.roboto.fonts/check/italic_angle",
  29. "com.roboto.fonts/check/fs_type",
  30. "com.roboto.fonts/check/vendorid",
  31. "com.roboto.fonts/check/digit_widths",
  32. "com.roboto.fonts/check/features",
  33. ]
  34. @check(
  35. id="com.roboto.fonts/check/vertical_metrics",
  36. )
  37. def com_roboto_fonts_check_vertical_metrics(ttFont):
  38. """Check vertical metrics are correct"""
  39. failed = []
  40. expected = {
  41. # android requires this, and web fonts expect this
  42. ("head", "yMin"): -555,
  43. ("head", "yMax"): 2163,
  44. # test hhea ascent, descent, and lineGap to be equal to Roboto v1 values
  45. ("hhea", "descent"): -500,
  46. ("hhea", "ascent"): 1900,
  47. ("hhea", "lineGap"): 0,
  48. # test OS/2 vertical metrics to be equal to old OS/2 win values
  49. # since fsSelection bit 7 is now enabled
  50. ("OS/2", "sTypoDescender"): -512,
  51. ("OS/2", "sTypoAscender"): 1536,
  52. ("OS/2", "sTypoLineGap"): 102,
  53. ("OS/2", "usWinDescent"): 512,
  54. ("OS/2", "usWinAscent"): 1946,
  55. }
  56. for (table, k), v in expected.items():
  57. font_val = getattr(ttFont[table], k)
  58. if font_val != v:
  59. failed.append((table, k, v, font_val))
  60. if not failed:
  61. yield PASS, "Fonts have correct vertical metrics"
  62. else:
  63. msg = "\n".join(
  64. [
  65. f"- {tbl}.{k} is {font_val} it should be {v}"
  66. for tbl, k, v, font_val in failed
  67. ]
  68. )
  69. yield FAIL, f"Fonts have incorrect vertical metrics:\n{msg}"
  70. @check(
  71. id="com.roboto.fonts/check/oblique_bits_not_set",
  72. )
  73. def com_roboto_fonts_check_oblique_bits_not_set(ttFont):
  74. """Check oblique bits are not set in fonts"""
  75. if ttFont['OS/2'].fsSelection & (1 << 9) != 0:
  76. yield FAIL, "fsSelection bit 9 (Oblique) must not be enabled"
  77. else:
  78. yield PASS, "fsSelection bit 9 is disabled"
  79. @check(
  80. id="com.roboto.fonts/check/unique_id",
  81. )
  82. def com_roboto_fonts_check_unique_id(ttFont):
  83. """Check font unique id is correct"""
  84. family_name = font_family(ttFont)
  85. style = font_style(ttFont)
  86. if style != "Regular":
  87. expected = f"{family_name} {style}"
  88. else:
  89. expected = f"{family_name}"
  90. font_unique_id = ttFont['name'].getName(3, 3, 1, 1033).toUnicode()
  91. if font_unique_id == expected:
  92. yield PASS, "Unique ID is correct"
  93. else:
  94. yield FAIL, f"Unique ID, '{font_unique_id}' is incorrect. It should be '{expected}'"
  95. @check(
  96. id="com.roboto.fonts/check/hinting",
  97. )
  98. def com_roboto_fonts_check_hinting(ttFont):
  99. """Check glyphs have hinting"""
  100. missing_hints = []
  101. # we can ignore these according to Mike D
  102. # https://github.com/TypeNetwork/Roboto/issues/70#issuecomment-641221200
  103. ignore = ['.notdef', 'uni0488', 'uni0489', 'uniFFFC', 'uniFFFD']
  104. for glyph_name in ttFont.getGlyphOrder():
  105. glyph = ttFont['glyf'][glyph_name]
  106. if glyph.numberOfContours <= 0:
  107. continue
  108. if len(glyph.program.bytecode) <= 0 and glyph_name not in ignore:
  109. missing_hints.append(glyph_name)
  110. if missing_hints:
  111. yield FAIL, f"Following glyphs are missing hinting {missing_hints}"
  112. else:
  113. yield PASS, "All glyphs are hinted"
  114. profile.auto_register(globals())
  115. profile.test_expected_checks(ROBOTO_PROFILE_CHECKS, exclusive=True)