Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ A more detailed list of changes is available in the corresponding milestones for
- **[com.google.fonts/check/colorfont_tables]:** Fonts must have neither or both the tables `COLR` and `SVG`. (issue #3886)
- **[com.google.fonts/check/description/noto_has_article]:** Noto fonts must have an ARTICLE.en_us.html file. (issue #3841)
- **[com.google.fonts/check/slant_direction]:** Check slant direction of outline to match values of slnt axis extrema. (PR #3910)
- **[com.google.fonts/check/color_cpal_brightness]:** Warn if COLRv0 layers are colored too dark or too bright instead of foreground color. (PR #3908)

### BugFixes
- **[com.adobe.fonts/check/varfont/valid_default_instance_nameids]:** The check did not account for nameID 17. (issue #3895)
Expand Down
56 changes: 56 additions & 0 deletions Lib/fontbakery/profiles/googlefonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
'com.google.fonts/check/render_own_name',
'com.google.fonts/check/STAT',
'com.google.fonts/check/colorfont_tables',
'com.google.fonts/check/color_cpal_brightness',
]

GOOGLEFONTS_PROFILE_CHECKS = \
Expand Down Expand Up @@ -6248,6 +6249,61 @@ def com_google_fonts_check_colorfont_tables(ttFont):
else:
yield PASS, "Looks good!"


@check(
id = "com.google.fonts/check/color_cpal_brightness",
rationale = """
Layers of a COLRv0 font should not be too dark or too bright. When layer colors
are set explicitly, they can't be changed and they may turn out illegible
against dark or bright backgrounds.

While traditional color-less fonts can be colored in design apps or CSS, a
black color definition in a COLRv0 font actually means that that layer will be
rendered in black regardless of the background color. This leads to text
becoming invisible against a dark background, for instance when using a dark
theme in a web browser or operating system.

This check ensures that layer colors are at least 10% bright and at most 90%
bright, when not already set to the current color (0xFFFF).
""",
proposal = 'https://github.com/googlefonts/fontbakery/pull/3908'
)
def com_google_fonts_check_color_cpal_brightness(config, ttFont):
"""Color layers should have a minimum brightness"""
from fontbakery.utils import pretty_print_list

def color_brightness(hex_value):
'''Generic color brightness formula'''
return (hex_value[0] * 299 + hex_value[1] * 587 + hex_value[2] * 114) / 1000

minimum_brightness = 256 * .1
FOREGROUND_COLOR = 0xFFFF
dark_glyphs = []
if 'COLR' in ttFont.keys() and ttFont['COLR'].version == 0:
for key in ttFont['COLR'].ColorLayers:
for layer in ttFont['COLR'].ColorLayers[key]:
# 0xFFFF is the foreground color, ignore
if layer.colorID != FOREGROUND_COLOR:
hex_value = ttFont["CPAL"].palettes[0][layer.colorID]
layer_brightness = color_brightness(hex_value)
if (layer_brightness < minimum_brightness
or layer_brightness > 256 - minimum_brightness):
if key not in dark_glyphs:
dark_glyphs.append(key)
if dark_glyphs:
dark_glyphs = pretty_print_list(config, sorted(dark_glyphs))
yield WARN,\
Message('glyphs-too-dark-or-too-bright',
f"The following glyphs have layers that are too bright or"
f" too dark: {dark_glyphs}.\n"
f"\n"
f" To fix this, please either set the color definitions of all"
f" layers in question to current color (0xFFFF), or alter"
f" the brightness of these layers significantly.")
else:
yield PASS, "Looks good!"


@check(
id = 'com.google.fonts/check/description/noto_has_article',
conditions = ['is_noto'],
Expand Down
Binary file not shown.
29 changes: 21 additions & 8 deletions tests/profiles/googlefonts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4218,10 +4218,8 @@ def test_check_STAT(fps, new_stat, result):
@patch("freetype.Face", side_effect=ImportError)
def test_check_override_freetype_rasterizer(mock_import_error):
"""Check that overridden test yields FAIL rather than SKIP."""
check = CheckTester(
googlefonts_profile,
f"com.adobe.fonts/check/freetype_rasterizer{OVERRIDE_SUFFIX}",
)
check = CheckTester(googlefonts_profile,
f"com.adobe.fonts/check/freetype_rasterizer{OVERRIDE_SUFFIX}")

font = TEST_FILE("cabin/Cabin-Regular.ttf")
msg = assert_results_contain(check(font), FAIL, "freetype-not-installed")
Expand Down Expand Up @@ -4263,15 +4261,30 @@ def test_check_colorfont_tables():
f'with a good font without SVG or COLR tables.')


def test_check_color_cpal_brightness():
"""Color layers should have a minimum brightness"""
check = CheckTester(googlefonts_profile,
"com.google.fonts/check/color_cpal_brightness")

font = TEST_FILE("color_fonts/AmiriQuranColored_too_dark.ttf")
assert_results_contain(check(font),
WARN, 'glyphs-too-dark-or-too-bright',
'with a colrv0 font with doo dark layers')

font = TEST_FILE("color_fonts/AmiriQuranColored.ttf")
assert_PASS(check(font),
'with a colrv0 font with good layer colors')


def test_check_noto_has_article():
"""Noto fonts must have an ARTICLE.en_us.html file"""
check = CheckTester(googlefonts_profile,
"com.google.fonts/check/description/noto_has_article")

ttFont = TTFont(TEST_FILE("notosanskhudawadi/NotoSansKhudawadi-Regular.ttf"))
assert_PASS(check(ttFont), "with a good font")
font = TEST_FILE("notosanskhudawadi/NotoSansKhudawadi-Regular.ttf")
assert_PASS(check(font), "with a good font")

ttFont = TTFont(TEST_FILE("noto_sans_tamil_supplement/NotoSansTamilSupplement-Regular.ttf"))
assert_results_contain(check(ttFont),
font = TEST_FILE("noto_sans_tamil_supplement/NotoSansTamilSupplement-Regular.ttf")
assert_results_contain(check(font),
FAIL, 'missing-article',
"with a bad font")