• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Hotfix a set of 'upstream' Noto CJK fonts to comply with fonts.google.com
3requirements. The following hotfixes are made:
4
5* Reconstruct fvar/STAT tables to remove any weights which do not
6  comply to the fonts.google.com expectations.
7* Rewrite the license description within the fonts to be the standard OFL
8  text used in other fonts.
9* Replace the copyright sign © in the name table with ASCII '(c)'.
10* Rename the variable fonts using the GF Family[axes].ttf format.
11* Run various other source fixes using gftools.fix.
12* Restore the correct hhea ascent = 1160 and descent = -288.
13"""
14
15from gftools.util.google_fonts import _KNOWN_WEIGHTS
16from gftools.fix import fix_font
17from axisregistry import build_name_table, build_fvar_instances, build_stat
18from fontTools.ttLib import TTFont
19from fontTools.ttLib.tables._f_v_a_r import NamedInstance
20from gftools.constants import (
21    NAMEID_FONT_SUBFAMILY_NAME,
22    NAMEID_TYPOGRAPHIC_SUBFAMILY_NAME,
23)
24from fontbakery.profiles.googlefonts import com_google_fonts_check_font_names
25from fontbakery.profiles.googlefonts_conditions import expected_font_names
26import argparse
27import re
28import os
29
30HOTFIX_NUMBER = 2
31
32OFL_DESCRIPTION = "This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL"
33
34parser = argparse.ArgumentParser(
35    description="Hotfix Noto CJK VF TTFs to Google Fonts standard"
36)
37parser.add_argument("--output-dir", default=".", help="output directory")
38parser.add_argument("fonts", metavar="N", type=str, nargs="+", help="fonts to fix")
39
40args = parser.parse_args()
41
42if not os.path.exists(args.output_dir):
43    os.makedirs(args.output_dir)
44
45if "" in _KNOWN_WEIGHTS:
46    del _KNOWN_WEIGHTS[""]
47if "Hairline" in _KNOWN_WEIGHTS:
48    del _KNOWN_WEIGHTS["Hairline"]
49
50
51def scratch_font(ttfont):
52    # Trash all the names from STAT/fvar and start again.
53    deletable_names = set()
54    if "STAT" in ttfont:
55        stat = ttfont["STAT"].table
56        deletable_names.add(stat.ElidedFallbackNameID)
57        for av in stat.AxisValueArray.AxisValue:
58            deletable_names.add(av.ValueNameID)
59        for axis in stat.DesignAxisRecord.Axis:
60            deletable_names.add(axis.AxisNameID)
61        del ttfont["STAT"]
62
63    fvar = ttfont["fvar"]
64    for axis in fvar.axes:
65        deletable_names.remove(axis.axisNameID)
66    for instance in fvar.instances:
67        deletable_names.add(instance.subfamilyNameID)
68        deletable_names.add(instance.postscriptNameID)
69    for name_id in deletable_names:
70        ttfont["name"].removeNames(name_id)
71    fvar.instances = []
72
73    # Drop 0x411 font names
74    ttfont["name"].names = [x for x in ttfont["name"].names if x.langID == 0x409]
75
76
77def fix_copyright(ttfont):
78    ttfont["name"].setName(
79        ttfont["name"].getName(0, 3, 1).toUnicode().replace("©", "(c)"), 0, 3, 1, 0x409
80    )
81    ttfont["name"].setName(OFL_DESCRIPTION, 13, 3, 1, 0x409)
82
83
84def fix_version(ttfont):
85    ttfont["name"].setName(
86        ttfont["name"]
87        .getName(5, 3, 1)
88        .toUnicode()
89        .replace(";hotconv", f"-H{HOTFIX_NUMBER};hotconv"),
90        5,
91        3,
92        1,
93        0x409,
94    )
95
96
97def fix_hhea_ascent(ttfont, sans=True):
98    if sans:
99        ttfont["hhea"].ascender = 1160
100        ttfont["hhea"].descent = -288
101    else:
102        ttfont["hhea"].ascender = 1151
103        ttfont["hhea"].descent = -286
104
105
106for font in args.fonts:
107    ttfont = TTFont(font)
108    scratch_font(ttfont)
109    fix_copyright(ttfont)
110    fix_version(ttfont)
111    fix_hhea_ascent(ttfont, "Sans" in font)
112    fix_font(ttfont, include_source_fixes=True)
113    build_name_table(ttfont, siblings=[])
114    build_fvar_instances(ttfont)
115    build_stat(ttfont, [])
116    if "DSIG" in ttfont:
117        del ttfont["DSIG"]
118
119    axis_tags = sorted([ax.axisTag for ax in ttfont["fvar"].axes])
120    axis_tags = ",".join(axis_tags)
121    newname = os.path.basename(font).replace("-VF.ttf", "[%s].ttf" % axis_tags)
122    newname = re.sub("CJK(..)", lambda x: x[0][-2:].upper(), newname)
123    ttfont.save(os.path.join(args.output_dir, newname))
124