mirror of
https://bjh21.me.uk/bedstead/.git
synced 2026-07-09 21:43:06 -04:00
My GNU Emacs configuration ended up using this to select its default font, so it should remain constant within a major version.
97 lines
3.4 KiB
Python
Executable File
97 lines
3.4 KiB
Python
Executable File
#! /usr/bin/python3
|
|
|
|
# SPDX-License-Identifier: CC0-1.0
|
|
|
|
# This is a script to check the backward compatibility of fonts, and
|
|
# specifically of Bedstead. It takes two font files as arguments and
|
|
# checks whether upgrades from the first to the second will break
|
|
# anything. It should fail on anything that would require a change of
|
|
# major version number.
|
|
#
|
|
# Things that are checked:
|
|
#
|
|
# Glyph names. Existing PostScript files that refer to specific glyph
|
|
# names should continue to work. The script checks that all glyph
|
|
# names in the old font still exist, but not that they look right.
|
|
#
|
|
# Code points. Anything using a font through the 'cmap' table should
|
|
# continue to work. That means that any 'cmap' that exists should
|
|
# continue to exist, and that any mapping through any 'cmap' should
|
|
# continue to work. As with glyph names, the script checks for the
|
|
# existence of mappings, but not their content.
|
|
#
|
|
# Names. Applications use a font's name to refer to it. This script
|
|
# checks that the subset of names for which this seems reasonable
|
|
# match between the old and new fonts.
|
|
#
|
|
# Vendor ID. At least some versions of GNU Emacs like to use the
|
|
# OS/2.achVendID field to select fonts. So if that changes, Emacs
|
|
# might not find your favourite font.
|
|
|
|
from argparse import ArgumentParser
|
|
from fontTools import ttLib
|
|
from sys import exit
|
|
|
|
parser = ArgumentParser()
|
|
parser.add_argument("old")
|
|
parser.add_argument("new")
|
|
|
|
cfg = parser.parse_args()
|
|
|
|
ttold = ttLib.TTFont(cfg.old)
|
|
ttnew = ttLib.TTFont(cfg.new)
|
|
|
|
failed = False
|
|
|
|
def fail(msg):
|
|
failed = True
|
|
print(f"FAIL: {msg}")
|
|
|
|
if not (set(ttold.getGlyphOrder()) <= set(ttnew.getGlyphOrder())):
|
|
fail("Glyphs vanished: "
|
|
f"{set(ttold.getGlyphOrder()) - set(ttnew.getGlyphOrder())!r}")
|
|
|
|
for cmapold in ttold['cmap'].tables:
|
|
cmapnew = ttnew['cmap'].getcmap(cmapold.platformID, cmapold.platEncID)
|
|
if cmapnew == None:
|
|
fail("No cmap in new font for "
|
|
f"{(cmapold.platformID,cmapold.platEncID)}")
|
|
elif not (set(cmapold.cmap.keys()) <= set(cmapnew.cmap.keys())):
|
|
fail("Code points vanished from "
|
|
f"{(cmapold.platformID,cmapold.platEncID)}: "
|
|
f"{set(cmapold.cmap.keys()) - set(cmapnew.cmap.keys())!r}")
|
|
|
|
# Names that might be used to specify fonts.
|
|
specnames = {
|
|
1, # Font family name
|
|
2, # Font subfamily name
|
|
4, # Full font name
|
|
6, # PostScript FontName
|
|
16, # Typographic family name
|
|
17, # Typographic subfamily name
|
|
18, # Compatible full name
|
|
20, # PostScript CID findfont name
|
|
21, # WWS family name
|
|
22, # WWS subfamily name
|
|
25, # Variations PostScript name prefix
|
|
}
|
|
for oldname in ttold['name'].names:
|
|
if oldname.nameID in specnames:
|
|
newname = ttnew['name'].getName(oldname.nameID, oldname.platformID,
|
|
oldname.platEncID, oldname.langID)
|
|
if newname == None:
|
|
fail("No name in new font for "
|
|
f"nameID={oldname.nameID}, platformID={oldname.platformID}, "
|
|
f"platEncID={oldname.platEncID}, langID={oldname.langID}")
|
|
if newname.string != oldname.string:
|
|
fail("Name mismatch for "
|
|
f"nameID={oldname.nameID}, platformID={oldname.platformID}, "
|
|
f"platEncID={oldname.platEncID}, langID={oldname.langID}")
|
|
|
|
|
|
if ttold['OS/2'].achVendID != ttnew['OS/2'].achVendID:
|
|
fail("Vendor ID mismatch")
|
|
|
|
if failed:
|
|
exit(1)
|