diff --git a/Makefile b/Makefile index ff684625b..13f1717b0 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ # limitations under the License. EMOJI = NotoColorEmoji -font: $(EMOJI).ttf +EMOJI_WINDOWS = NotoColorEmoji_WindowsCompatible +all: $(EMOJI).ttf $(EMOJI_WINDOWS).ttf CFLAGS = -std=c99 -Wall -Wextra `pkg-config --cflags --libs cairo` LDFLAGS = -lm `pkg-config --libs cairo` @@ -108,7 +109,7 @@ RESIZED_FLAG_FILES = $(addprefix $(RESIZED_FLAGS_DIR)/, $(FLAG_NAMES)) ifndef MISSING_PY_TOOLS FLAG_GLYPH_NAMES = $(shell $(PYTHON) flag_glyph_name.py $(FLAGS)) else -FLAG_GLYPH_NAMES = +FLAG_GLYPH_NAMES = endif RENAMED_FLAG_NAMES = $(FLAG_GLYPH_NAMES:%=emoji_%.png) RENAMED_FLAG_FILES = $(addprefix $(RENAMED_FLAGS_DIR)/, $(RENAMED_FLAG_NAMES)) @@ -199,8 +200,11 @@ $(COMPRESSED_DIR)/%.png: $(QUANTIZED_DIR)/%.png | check_tools $(COMPRESSED_DIR) # ... # Run make without -j if this happens. -%.ttx: %.ttx.tmpl $(ADD_GLYPHS) $(ALL_COMPRESSED_FILES) - @$(PYTHON) $(ADD_GLYPHS) -f "$<" -o "$@" -d "$(COMPRESSED_DIR)" $(ADD_GLYPHS_FLAGS) +$(EMOJI).tmpl.ttx: $(EMOJI).tmpl.ttx.tmpl $(ADD_GLYPHS) $(ALL_COMPRESSED_FILES) + $(PYTHON) $(ADD_GLYPHS) -f "$<" -o "$@" -d "$(COMPRESSED_DIR)" $(ADD_GLYPHS_FLAGS) + +$(EMOJI_WINDOWS).tmpl.ttx: $(EMOJI).tmpl.ttx.tmpl $(ADD_GLYPHS) $(ALL_COMPRESSED_FILES) + $(PYTHON) $(ADD_GLYPHS) --add_cmap4 --add_glyf -f "$<" -o "$@" -d "$(COMPRESSED_DIR)" $(ADD_GLYPHS_FLAGS) %.ttf: %.ttx @rm -f "$@" @@ -215,6 +219,16 @@ $(EMOJI).ttf: check_sequence $(EMOJI).tmpl.ttf $(EMOJI_BUILDER) $(PUA_ADDER) \ @mv "$@-with-pua-varsel" "$@" @rm "$@-with-pua" +$(EMOJI_WINDOWS).ttf: check_sequence $(EMOJI_WINDOWS).tmpl.ttf $(EMOJI_BUILDER) $(PUA_ADDER) \ + $(ALL_COMPRESSED_FILES) | check_tools + + @$(PYTHON) $(EMOJI_BUILDER) -O $(SMALL_METRICS) -V $(word 2,$^) "$@" "$(COMPRESSED_DIR)/emoji_u" + @$(PYTHON) $(PUA_ADDER) "$@" "$@-with-pua" + @$(VS_ADDER) -vs 2640 2642 2695 --dstdir '.' -o "$@-with-pua-varsel" "$@-with-pua" + @mv "$@-with-pua-varsel" "$@" + @rm "$@-with-pua" + + check_sequence: ifdef BYPASS_SEQUENCE_CHECK @echo Bypassing the emoji sequence checks @@ -223,7 +237,7 @@ else endif clean: - rm -f $(EMOJI).ttf $(EMOJI).tmpl.ttf $(EMOJI).tmpl.ttx + rm -f $(EMOJI).ttf $(EMOJI_WINDOWS).ttf $(EMOJI).tmpl.ttf $(EMOJI_WINDOWS).tmpl.ttf $(EMOJI).tmpl.ttx $(EMOJI_WINDOWS).tmpl.ttx rm -f waveflag rm -rf $(BUILD_DIR) diff --git a/add_glyphs.py b/add_glyphs.py index dd788ad96..bc7e16513 100644 --- a/add_glyphs.py +++ b/add_glyphs.py @@ -18,6 +18,9 @@ import sys from fontTools import ttx from fontTools.ttLib.tables import otTables +from fontTools.pens.ttGlyphPen import TTGlyphPen +from fontTools.ttLib.tables._c_m_a_p import CmapSubtable +from fontTools.ttLib import newTable import add_emoji_gsub import add_aliases @@ -139,7 +142,7 @@ def get_font_cmap(font): return font['cmap'].tables[0].cmap -def add_glyph_data(font, seqs, seq_to_advance, vadvance): +def add_glyph_data(font, seqs, seq_to_advance, vadvance, add_glyf): """Add hmtx and GlyphOrder data for all sequences in seqs, and ensures there's a cmap entry for each single-codepoint sequence. Seqs not in seq_to_advance will get a zero advance.""" @@ -163,6 +166,16 @@ def add_glyph_data(font, seqs, seq_to_advance, vadvance): hmtx = font['hmtx'].metrics vmtx = font['vmtx'].metrics + # Add glyf table so empty glyphs will be added to ensure compatibility + # with systems requiring a glyf table, like Windows 10. + if add_glyf: + pen = TTGlyphPen(None) + empty_glyph = pen.glyph() + font['loca'] = newTable("loca") + font['glyf'] = glyf_table = newTable("glyf") + glyf_table.glyphOrder = font.getGlyphOrder() + glyf_table.glyphs = {g: empty_glyph for g in glyf_table.glyphOrder} + # We don't expect sequences to be in the glyphOrder, since we removed all the # single-cp sequences from it and don't expect it to already contain names # corresponding to multiple-cp sequencess. But just in case, we use @@ -186,11 +199,12 @@ def add_glyph_data(font, seqs, seq_to_advance, vadvance): if name not in reverseGlyphMap: font.glyphOrder.append(name) updatedGlyphOrder=True + if add_glyf: + glyf_table[name] = empty_glyph if updatedGlyphOrder: delattr(font, '_reverseGlyphOrderDict') - def add_aliases_to_cmap(font, aliases): """Some aliases might map a single codepoint to some other sequence. These should map directly to the glyph for that sequence in the cmap. (Others will @@ -327,14 +341,30 @@ def add_ligature_sequences(font, seqs, aliases): for seq, name in pairs: add_ligature(lookup, cmap, seq, name) +def add_cmap_format_4(font): + """Add cmap format 4 table for Windows support, based on the + format 12 cmap.""" -def update_font_data(font, seq_to_advance, vadvance, aliases): + cmap = get_font_cmap(font) + + newtable = CmapSubtable.newSubtable(4) + newtable.platformID = 3 + newtable.platEncID = 1 + newtable.language = 0 + + # Format 4 only has unicode values 0x0000 to 0xFFFF + newtable.cmap = {cp: name for cp, name in cmap.items() if cp <= 0xFFFF} + + font['cmap'].tables.append(newtable) + +def update_font_data(font, seq_to_advance, vadvance, aliases, add_cmap4, add_glyf): """Update the font's cmap, hmtx, GSUB, and GlyphOrder tables.""" seqs = get_all_seqs(font, seq_to_advance) - add_glyph_data(font, seqs, seq_to_advance, vadvance) + add_glyph_data(font, seqs, seq_to_advance, vadvance, add_glyf) add_aliases_to_cmap(font, aliases) add_ligature_sequences(font, seqs, aliases) - + if add_cmap4: + add_cmap_format_4(font) def apply_aliases(seq_dict, aliases): """Aliases is a mapping from sequence to replacement sequence. We can use @@ -350,7 +380,7 @@ def apply_aliases(seq_dict, aliases): return usable_aliases -def update_ttx(in_file, out_file, image_dirs, prefix, ext, aliases_file): +def update_ttx(in_file, out_file, image_dirs, prefix, ext, aliases_file, add_cmap4, add_glyf): if ext != '.png': raise Exception('extension "%s" not supported' % ext) @@ -374,7 +404,7 @@ def update_ttx(in_file, out_file, image_dirs, prefix, ext, aliases_file): vadvance = font['vhea'].advanceHeightMax if 'vhea' in font else lineheight - update_font_data(font, seq_to_advance, vadvance, aliases) + update_font_data(font, seq_to_advance, vadvance, aliases, add_cmap4, add_glyf) font.saveXML(out_file) @@ -397,11 +427,15 @@ def main(): parser.add_argument( '-a', '--aliases', help='process alias table', const='emoji_aliases.txt', nargs='?', metavar='file') + parser.add_argument( + '--add_cmap4', help='add cmap format 4 table', dest='add_cmap4', action='store_true') + parser.add_argument( + '--add_glyf', help='add glyf and loca tables', dest='add_glyf', action='store_true') args = parser.parse_args() update_ttx( args.in_file, args.out_file, args.image_dirs, args.prefix, args.ext, - args.aliases) + args.aliases, args.add_cmap4, args.add_glyf) if __name__ == '__main__': diff --git a/fonts/NotoColorEmoji.ttf b/fonts/NotoColorEmoji.ttf index 6c7da1ec8..b836e93f2 100644 Binary files a/fonts/NotoColorEmoji.ttf and b/fonts/NotoColorEmoji.ttf differ diff --git a/fonts/NotoColorEmoji_WindowsCompatible.ttf b/fonts/NotoColorEmoji_WindowsCompatible.ttf new file mode 100644 index 000000000..6cf68f3ed Binary files /dev/null and b/fonts/NotoColorEmoji_WindowsCompatible.ttf differ