diff options
author | Rasmus Andersson <rasmus@notion.se> | 2021-03-29 22:30:03 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2021-03-29 22:30:03 +0300 |
commit | 637d0eb1861100028c1fb5159206a8059a658c9b (patch) | |
tree | 0e9cbee88a19873c72748867909a4cef1c21181d /misc | |
parent | bff8f875a27e130145e68612e2ed54d174ccbdcd (diff) | |
download | inter-637d0eb1861100028c1fb5159206a8059a658c9b.tar.xz |
web: Disable subset fonts as it turns out pyftsubset does not correctly handle substitution features causing subs like ccmp to break
Diffstat (limited to 'misc')
-rwxr-xr-x | misc/tools/subset.py | 151 |
1 files changed, 90 insertions, 61 deletions
diff --git a/misc/tools/subset.py b/misc/tools/subset.py index 37ed9a596..095c7ed3c 100755 --- a/misc/tools/subset.py +++ b/misc/tools/subset.py @@ -15,6 +15,11 @@ sys.path.append(dirname(abspath(__file__))) from common import BASEDIR, VENVDIR +# FORCE can be set to True to subset all fonts regardless if the input source +# font has changed or not +FORCE = False + + # fonts to subset FONTS = [ @@ -109,6 +114,9 @@ SYMBOL_UNICODES = [ ] +SELF_SCRIPT_MTIME = 0 + + def main(argv): # defines subsets. # Ranges are inclusive. @@ -181,14 +189,22 @@ def main(argv): *genCompactIntRanges(SYMBOL_UNICODES) ), - defsubset('alternates', - # all private-use codepoints are mapped to alternate glyphs, normally accessed by - # OpenType features. - range(0xE000, 0xF8FF), - ), + # defsubset('alternates', + # # all private-use codepoints are mapped to alternate glyphs, normally accessed by + # # OpenType features. + # range(0xE000, 0xF8FF), + # ), + # Note: Disabled so that alternates are all added automatically to the "extra" set. ) + global SELF_SCRIPT_MTIME + SELF_SCRIPT_MTIME = os.path.getmtime(__file__) + + # XXX DEBUG + global FONTS + FONTS = FONTS[1:2] + # generate subset fonts with ProcPool() as procpool: for fontinfo in FONTS: @@ -207,49 +223,6 @@ def main(argv): f.write(css) -def genCSS(fontinfo, subsets): - outfileTemplate = pjoin(BASEDIR, fontinfo['outfile']) - - css_family = fontinfo.get('css_family', 'Inter') - css_style = fontinfo.get('css_style', 'normal') - css_weight = fontinfo.get('css_weight', '400') - css_extra = fontinfo.get('css_extra', '') - if len(css_extra) > 0: - css_extra = '\n ' + css_extra - css = [] - - for subset in list(subsets) + [{ 'name':'extra' }]: - outfile = outfileTemplate.format(subset=subset['name']) - # Read effective codepoint coverage. This may be greater than requested - # in case of OT features. For example, the Latin subset includes some common arrow - # glyphs since "->" is a ligature for "→". - font = ttLib.TTFont(outfile) - unicodes = set(getUnicodeMap(font)) - if min(unicodes) < 0x30: - # the "base" (latin) subset. extend it to include control codepoints - controlCodepoints, _ = genUnicodeRange([range(0x0000, 0x001F)]) - unicodes = unicodes.union(controlCodepoints) - _, unicodeRange = genUnicodeRange(genCompactIntRanges(unicodes)) - css.append(CSS_TEMPLATE.format( - comment=subset['name'], - filename=basename(outfile), - unicode_range=unicodeRange, - family=css_family, - style=css_style, - weight=css_weight, - extra=css_extra, - ).strip()) - - # From the CSS spec on unicode-range descriptor: - # "If the Unicode ranges overlap for a set of @font-face rules with the same family - # and style descriptor values, the rules are ordered in the reverse order they were - # defined; the last rule defined is the first to be checked for a given character." - # https://www.w3.org/TR/css-fonts-4/#unicode-range-desc - css.reverse() - - return '\n'.join(css) - - def subset_font(fontinfo, subsets, procpool): infile = pjoin(BASEDIR, fontinfo['infile']) outfileTemplate = pjoin(BASEDIR, fontinfo['outfile']) @@ -268,18 +241,26 @@ def subset_font(fontinfo, subsets, procpool): extraUnicodes = ucall - covered _, extraUnicodeRange = genUnicodeRange(extraUnicodes) outfile = outfileTemplate.format(subset='extra') - print("write", outfile) subset_range_async(procpool, infile, outfile, unicodeRange) def subset_range_async(procpool :ProcPool, infile :str, outfile :str, unicodeRange :str): - try: - if os.path.getmtime(outfile) > os.path.getmtime(infile): - # print('up-to-date %s -> %s' % (relpath(infile), relpath(outfile))) - return - except: - pass - procpool.apply_async( subset_range,(infile, outfile, unicodeRange) ) + if not FORCE: + try: + outmtime = os.path.getmtime(outfile) + if outmtime > os.path.getmtime(infile) and outmtime > SELF_SCRIPT_MTIME: + print('up-to-date %s -> %s' % (relpath(infile), relpath(outfile))) + return + except: + pass + procpool.apply_async( subset_range,(infile, outfile, unicodeRange), + error_callback=lambda err: onProcErr(procpool, err) ) + + +def onProcErr(procpool, err): + procpool.terminate() + raise err + sys.exit(1) def subset_range(infile :str, outfile :str, unicodeRange :str): @@ -289,6 +270,9 @@ def subset_range(infile :str, outfile :str, unicodeRange :str): pyftsubset, '--unicodes=' + unicodeRange, '--layout-features=*', + '--recommended-glyphs', + '--no-recalc-bounds', + '--no-prune-unicode-ranges', '--no-hinting', '--output-file=' + outfile, infile @@ -302,16 +286,18 @@ def subset_range(infile :str, outfile :str, unicodeRange :str): args, shell=False, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, # combine stdout & stderr into p.stdout + stderr=subprocess.PIPE, encoding='utf-8', # py3 ) - output = p.stdout.strip() if p.returncode != 0: - raise Exception('pyftsubset failed:\n%s\nInvocation:\n%s' % ( - output, + raise Exception( + 'pyftsubset failed:\n-- stdout:\n%s\n\n-- stderr:\n%s\n\n-- invocation:\n%s' % ( + p.stdout.strip(), + p.stderr.strip(), '\n '.join([repr(a) for a in args]), )) - + # sys.exit(p.returncode) + print("write", outfile) # (name, ...[int|range(int)]) -> { name:str codepoints:[int|range(int)] } def defsubset(name, *codepoints): @@ -382,6 +368,49 @@ def genCompactIntRanges(codepoints :[int]) -> [[int]]: return compact +def genCSS(fontinfo, subsets): + outfileTemplate = pjoin(BASEDIR, fontinfo['outfile']) + + css_family = fontinfo.get('css_family', 'Inter') + css_style = fontinfo.get('css_style', 'normal') + css_weight = fontinfo.get('css_weight', '400') + css_extra = fontinfo.get('css_extra', '') + if len(css_extra) > 0: + css_extra = '\n ' + css_extra + css = [] + + for subset in list(subsets) + [{ 'name':'extra' }]: + outfile = outfileTemplate.format(subset=subset['name']) + # Read effective codepoint coverage. This may be greater than requested + # in case of OT features. For example, the Latin subset includes some common arrow + # glyphs since "->" is a ligature for "→". + font = ttLib.TTFont(outfile) + unicodes = set(getUnicodeMap(font)) + if min(unicodes) < 0x30: + # the "base" (latin) subset. extend it to include control codepoints + controlCodepoints, _ = genUnicodeRange([range(0x0000, 0x001F)]) + unicodes = unicodes.union(controlCodepoints) + _, unicodeRange = genUnicodeRange(genCompactIntRanges(unicodes)) + css.append(CSS_TEMPLATE.format( + comment=subset['name'], + filename=basename(outfile), + unicode_range=unicodeRange, + family=css_family, + style=css_style, + weight=css_weight, + extra=css_extra, + ).strip()) + + # From the CSS spec on unicode-range descriptor: + # "If the Unicode ranges overlap for a set of @font-face rules with the same family + # and style descriptor values, the rules are ordered in the reverse order they were + # defined; the last rule defined is the first to be checked for a given character." + # https://www.w3.org/TR/css-fonts-4/#unicode-range-desc + css.reverse() + + return '\n'.join(css) + + def relpath(path): return os.path.relpath(path, os.getcwd()) |