diff --git a/colrv1/noflags.toml b/colrv1/noflags.toml index 74c89ee4b..899e33352 100644 --- a/colrv1/noflags.toml +++ b/colrv1/noflags.toml @@ -3437,7 +3437,10 @@ srcs = [ "../svg/emoji_u303d.svg", "../svg/emoji_u3297.svg", "../svg/emoji_u3299.svg", - "../svg/emoji_ufe82b.svg"] + "../svg/emoji_ufe82b.svg", + "subdivision-flags/emoji_u1f3f4_e0067_e0062_e0065_e006e_e0067_e007f.svg", + "subdivision-flags/emoji_u1f3f4_e0067_e0062_e0073_e0063_e0074_e007f.svg", + "subdivision-flags/emoji_u1f3f4_e0067_e0062_e0077_e006c_e0073_e007f.svg"] [master.regular.position] wght = 400 diff --git a/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0065_e006e_e0067_e007f.svg b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0065_e006e_e0067_e007f.svg new file mode 100644 index 000000000..df0b18991 --- /dev/null +++ b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0065_e006e_e0067_e007f.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0073_e0063_e0074_e007f.svg b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0073_e0063_e0074_e007f.svg new file mode 100644 index 000000000..d8c1bf35d --- /dev/null +++ b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0073_e0063_e0074_e007f.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0077_e006c_e0073_e007f.svg b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0077_e006c_e0073_e007f.svg new file mode 100644 index 000000000..525809140 --- /dev/null +++ b/colrv1/subdivision-flags/emoji_u1f3f4_e0067_e0062_e0077_e006c_e0073_e007f.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/colrv1_postproc.py b/colrv1_postproc.py index 9f65506a2..a41c0e9d8 100644 --- a/colrv1_postproc.py +++ b/colrv1_postproc.py @@ -4,7 +4,9 @@ Post-nanoemoji processing of the Noto COLRv1 Emoji file. For now substantially based on copying from a correct bitmap build. """ from absl import app +import functools from fontTools import ttLib +from fontTools.ttLib.tables import otTables as ot import map_pua_emoji from nototools import add_vs_cmap from nototools import unicode_data @@ -74,6 +76,16 @@ def _lookup_in_cmap(colr_font, codepoint): return next(iter(result)) +def _add_cmap_entries(colr_font, codepoint, glyph_name): + for table in colr_font["cmap"].tables: + if _is_variation_selector_cmap_table(table): + continue + if not _is_bmp(codepoint) and table.format == 4: + continue + table.cmap[codepoint] = gn_space + print(f"Map 0x{codepoint:04x} to {glyph_name}, format {table.format}") + + def _map_flag_tag_chars_to_space(colr_font): gn_space = _lookup_in_cmap(colr_font, ord(" ")) @@ -88,20 +100,56 @@ def _map_flag_tag_chars_to_space(colr_font): # CBDT maps these things to space based on hb-shape testing # Android fontchain_lint is unhappy if no such mapping exists - for table in colr_font["cmap"].tables: - if _is_variation_selector_cmap_table(table): - continue - for cp in tag_cps: - if not _is_bmp(cp) and table.format == 4: - continue - table.cmap[cp] = gn_space - print(f"Map 0x{cp:04x} to space, format {table.format}") + for cp in tag_cps: + _add_cmap_entries(colr_font, cp, gn_space) def _is_bmp(cp): return cp in range(0x0000, 0xFFFF + 1) +def _ligaset_for_glyph(lookup_list, glyph_name): + for lookup in lookup_list.Lookup: + if lookup.LookupType != 4: + continue + for liga_set in lookup.SubTable: + if glyph_name in liga_set.ligatures: + return liga_set.ligatures[glyph_name] + return None + + +def _Cmap(ttfont): + + def _Reducer(acc, u): + acc.update(u) + return acc + + unicode_cmaps = (t.cmap for t in ttfont['cmap'].tables if t.isUnicode()) + return functools.reduce(_Reducer, unicode_cmaps, {}) + + +def _map_empty_flag_tag_to_black_flag(colr_font): + # fontchain_lint wants direct support for empty flag tags + # so map them to the default flag to match cbdt behavior + + # if the emoji font starts using extensions this code will require revision + + cmap = _Cmap(colr_font) + black_flag_glyph = cmap[0x1f3f4] + cancel_tag_glyph = cmap[0xe007f] + lookup_list = colr_font["GSUB"].table.LookupList + liga_set = _ligaset_for_glyph(lookup_list, black_flag_glyph) + assert liga_set is not None, "There should be existing ligatures using black flag" + + # Map black flag + cancel tag to just black flag + # Since this is the ligature set for black flag, component is just cancel tag + # Since we only have one component its safe to put our rule at the front + liga = ot.Ligature() + liga.Component = [cancel_tag_glyph] + liga.LigGlyph = black_flag_glyph + liga_set.insert(0, liga) + + def main(argv): if len(argv) != 3: raise ValueError("Must have two args, a COLRv1 font and a CBDT emojicompat font") @@ -124,6 +172,8 @@ def main(argv): _map_flag_tag_chars_to_space(colr_font) + _map_empty_flag_tag_to_black_flag(colr_font) + colr_font.save('fonts/Noto-COLRv1-noflags.ttf') diff --git a/fonts/Noto-COLRv1-noflags.ttf b/fonts/Noto-COLRv1-noflags.ttf index cb2420ddd..78417f850 100644 Binary files a/fonts/Noto-COLRv1-noflags.ttf and b/fonts/Noto-COLRv1-noflags.ttf differ