Merge "Extract flag font from NotoColorEmoji" into sc-dev

This commit is contained in:
Kohsuke Yatoh
2021-06-29 00:40:27 +00:00
committed by Android (Google) Code Review
3 changed files with 67 additions and 65 deletions

View File

@@ -304,11 +304,6 @@ public class ForwardDeleteTest {
forwardDelete(state, 0); forwardDelete(state, 0);
state.assertEquals("|"); state.assertEquals("|");
// Regional indicator symbol + COMBINING ENCLOSING KEYCAP
state.setByString("| U+1F1FA U+20E3");
forwardDelete(state, 0);
state.assertEquals("|");
// COMBINING ENCLOSING KEYCAP + emoji modifier // COMBINING ENCLOSING KEYCAP + emoji modifier
state.setByString("| '1' U+20E3 U+1F3FB"); state.setByString("| '1' U+20E3 U+1F3FB");
forwardDelete(state, 0); forwardDelete(state, 0);
@@ -408,11 +403,6 @@ public class ForwardDeleteTest {
// forwardDelete(state, 0); // forwardDelete(state, 0);
// state.assertEquals("|"); // state.assertEquals("|");
// Regional indicator symbol + emoji modifier
state.setByString("| U+1F1FA U+1F3FB");
forwardDelete(state, 0);
state.assertEquals("|");
// Emoji modifier + regional indicator symbol // Emoji modifier + regional indicator symbol
state.setByString("| U+1F466 U+1F3FB U+1F1FA"); state.setByString("| U+1F466 U+1F3FB U+1F1FA");
forwardDelete(state, 0); forwardDelete(state, 0);

View File

@@ -1331,6 +1331,9 @@
<family lang="und-Zsye"> <family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmoji.ttf</font> <font weight="400" style="normal">NotoColorEmoji.ttf</font>
</family> </family>
<family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmojiFlags.ttf</font>
</family>
<family lang="und-Zsym"> <family lang="und-Zsym">
<font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font> <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
</family> </family>

View File

@@ -117,13 +117,14 @@ def get_emoji_map(font):
reverse_cmap = {glyph: code for code, glyph in emoji_map.items() if not contains_pua(code) } reverse_cmap = {glyph: code for code, glyph in emoji_map.items() if not contains_pua(code) }
# Add variation sequences # Add variation sequences
vs_dict = get_variation_sequences_cmap(font).uvsDict vs_cmap = get_variation_sequences_cmap(font)
for vs in vs_dict: if vs_cmap:
for base, glyph in vs_dict[vs]: for vs in vs_cmap.uvsDict:
if glyph is None: for base, glyph in vs_cmap.uvsDict[vs]:
emoji_map[(base, vs)] = emoji_map[base] if glyph is None:
else: emoji_map[(base, vs)] = emoji_map[base]
emoji_map[(base, vs)] = glyph else:
emoji_map[(base, vs)] = glyph
# Add GSUB rules # Add GSUB rules
ttfont = open_font(font) ttfont = open_font(font)
@@ -310,17 +311,12 @@ def parse_fonts_xml(fonts_xml_path):
def check_emoji_coverage(all_emoji, equivalent_emoji): def check_emoji_coverage(all_emoji, equivalent_emoji):
emoji_font = get_emoji_font() emoji_fonts = get_emoji_fonts()
check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji) check_emoji_font_coverage(emoji_fonts, all_emoji, equivalent_emoji)
def get_emoji_font(): def get_emoji_fonts():
emoji_fonts = [ return [ record.font for record in _all_fonts if 'Zsye' in record.scripts ]
record.font for record in _all_fonts
if 'Zsye' in record.scripts]
assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
return emoji_fonts[0]
def is_pua(x): def is_pua(x):
return 0xE000 <= x <= 0xF8FF or 0xF0000 <= x <= 0xFFFFD or 0x100000 <= x <= 0x10FFFD return 0xE000 <= x <= 0xF8FF or 0xF0000 <= x <= 0xFFFFD or 0x100000 <= x <= 0x10FFFD
@@ -331,58 +327,71 @@ def contains_pua(sequence):
else: else:
return is_pua(sequence) return is_pua(sequence)
def get_psname(ttf):
return str(next(x for x in ttf['name'].names
if x.platformID == 3 and x.platEncID == 1 and x.nameID == 6))
def check_emoji_compat(): def check_emoji_compat():
ttf = open_font(get_emoji_font()) for emoji_font in get_emoji_fonts():
meta = ttf['meta'] ttf = open_font(emoji_font)
assert meta, 'Compat font must have meta table' psname = get_psname(ttf)
assert 'Emji' in meta.data, 'meta table should have \'Emji\' data.'
def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): # If the font file is NotoColorEmoji, it must be Compat font.
coverage = get_emoji_map(emoji_font) if psname == 'NotoColorEmoji':
meta = ttf['meta']
assert meta, 'Compat font must have meta table'
assert 'Emji' in meta.data, 'meta table should have \'Emji\' data.'
def check_emoji_font_coverage(emoji_fonts, all_emoji, equivalent_emoji):
coverages = []
for emoji_font in emoji_fonts:
coverages.append(get_emoji_map(emoji_font))
errors = [] errors = []
for sequence in all_emoji: for sequence in all_emoji:
if not sequence in coverage: if all([sequence not in coverage for coverage in coverages]):
errors.append('%s is not supported in the emoji font.' % printable(sequence)) errors.append('%s is not supported in the emoji font.' % printable(sequence))
for sequence in coverage: for coverage in coverages:
if sequence in {0x0000, 0x000D, 0x0020}: for sequence in coverage:
# The font needs to support a few extra characters, which is OK if sequence in {0x0000, 0x000D, 0x0020}:
continue # The font needs to support a few extra characters, which is OK
continue
if contains_pua(sequence): if contains_pua(sequence):
# The font needs to have some PUA for EmojiCompat library. # The font needs to have some PUA for EmojiCompat library.
continue continue
if sequence not in all_emoji: if sequence not in all_emoji:
errors.append('%s support unexpected in the emoji font.' % printable(sequence)) errors.append('%s support unexpected in the emoji font.' % printable(sequence))
for first, second in equivalent_emoji.items(): for first, second in equivalent_emoji.items():
if first not in coverage or second not in coverage: for coverage in coverages:
continue # sequence will be reported missing if first not in coverage or second not in coverage:
if coverage[first] != coverage[second]: continue # sequence will be reported missing
errors.append('%s and %s should map to the same glyph.' % ( if coverage[first] != coverage[second]:
printable(first), errors.append('%s and %s should map to the same glyph.' % (
printable(second))) printable(first),
printable(second)))
for glyph in set(coverage.values()): for coverage in coverages:
maps_to_glyph = [ for glyph in set(coverage.values()):
seq for seq in coverage if coverage[seq] == glyph and not contains_pua(seq) ] maps_to_glyph = [
if len(maps_to_glyph) > 1: seq for seq in coverage if coverage[seq] == glyph and not contains_pua(seq) ]
# There are more than one sequences mapping to the same glyph. We if len(maps_to_glyph) > 1:
# need to make sure they were expected to be equivalent. # There are more than one sequences mapping to the same glyph. We
equivalent_seqs = set() # need to make sure they were expected to be equivalent.
for seq in maps_to_glyph: equivalent_seqs = set()
equivalent_seq = seq for seq in maps_to_glyph:
while equivalent_seq in equivalent_emoji: equivalent_seq = seq
equivalent_seq = equivalent_emoji[equivalent_seq] while equivalent_seq in equivalent_emoji:
equivalent_seqs.add(equivalent_seq) equivalent_seq = equivalent_emoji[equivalent_seq]
if len(equivalent_seqs) != 1: equivalent_seqs.add(equivalent_seq)
errors.append('The sequences %s should not result in the same glyph %s' % ( if len(equivalent_seqs) != 1:
printable(equivalent_seqs), errors.append('The sequences %s should not result in the same glyph %s' % (
glyph)) printable(equivalent_seqs),
glyph))
assert not errors, '%d emoji font errors:\n%s\n%d emoji font coverage errors' % (len(errors), '\n'.join(errors), len(errors)) assert not errors, '%d emoji font errors:\n%s\n%d emoji font coverage errors' % (len(errors), '\n'.join(errors), len(errors))