test_web.py 3.9 KB

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