From ba28c24d899c329cb1db6bef162ca32693b08db9 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Wed, 6 Feb 2019 13:21:33 +0100 Subject: New upstream version 0~20170802 --- scripts/build-v2.py | 61 +++++++++-------- scripts/lib/fontbuild/Build.py | 109 ++++++++++++++----------------- scripts/lib/fontbuild/generateGlyph.py | 116 +++++++++++---------------------- scripts/lib/fontbuild/instanceNames.py | 4 +- scripts/lib/fontbuild/markFeature.py | 39 ++++++----- scripts/lib/fontbuild/mix.py | 47 +++++++------ scripts/render.sh | 2 +- scripts/roboto_data.py | 18 ++--- scripts/run_android_tests.py | 31 +++++++-- scripts/run_exhaustive_tests.py | 2 +- scripts/run_general_tests.py | 48 +++++++++++--- scripts/run_web_tests.py | 36 ++++++---- scripts/temporary_touchups.py | 30 ++++----- scripts/touchup_for_android.py | 51 +++------------ scripts/touchup_for_cros.py | 60 +++++++++++++++++ scripts/touchup_for_web.py | 73 ++++++++++++++++++--- 16 files changed, 412 insertions(+), 315 deletions(-) create mode 100755 scripts/touchup_for_cros.py (limited to 'scripts') diff --git a/scripts/build-v2.py b/scripts/build-v2.py index 6026939..181c0ec 100644 --- a/scripts/build-v2.py +++ b/scripts/build-v2.py @@ -31,14 +31,9 @@ BASEDIR = os.path.abspath( # Masters -rg = Master("%s/src/v2/Roboto_Regular.ufo" % BASEDIR, - anchorPath="%s/res/anchors_regular.json" % BASEDIR) -bd = Master("%s/src/v2/Roboto_Bold.ufo" % BASEDIR, - anchorPath="%s/res/anchors_bold.json" % BASEDIR) -th = Master("%s/src/v2/Roboto_Thin.ufo" % BASEDIR, - anchorPath="%s/res/anchors_thin.json" % BASEDIR) - -# build condensed masters +rg = Master("%s/src/v2/Roboto-Regular.ufo" % BASEDIR) +bd = Master("%s/src/v2/Roboto-Bold.ufo" % BASEDIR) +th = Master("%s/src/v2/Roboto-Thin.ufo" % BASEDIR) lessCondensed = ( "plusminus bracketleft bracketright dieresis macron " @@ -65,7 +60,6 @@ def condenseFont(font, scale=.8, stemWidth=185): # for g in [f[name] for name in LC]: for g in f: if len(g) > 0: - # print g.name if g.name in lessCondensed: scale = xscale * 1.1 if g.name in uncondensed: @@ -83,39 +77,38 @@ def condenseFont(font, scale=.8, stemWidth=185): return f -proj = FontProject(rg.font, BASEDIR, "res/roboto.cfg", th.ffont) -#proj.incrementBuildNumber() +proj = FontProject(rg.font, BASEDIR, "res/roboto.cfg") -# FAMILYNAME = "Roboto 2 DRAFT" -# FAMILYNAME = "Roboto2" FAMILYNAME = "Roboto" proj.buildOTF = True #proj.compatible = True -proj.generateFont(th.font, "%s/Thin/Regular/Th"%FAMILYNAME) -proj.generateFont(Mix([th, rg], 0.45), "%s/Light/Regular/Lt"%FAMILYNAME) +proj.generateFont(th.font, "%s/Thin/Regular/Th" % FAMILYNAME) +proj.generateFont(Mix([th, rg], 0.45), "%s/Light/Regular/Lt" % FAMILYNAME) proj.generateFont(Mix([th, rg], RPoint(0.90, 0.92)), - "%s/Regular/Regular/Rg"%FAMILYNAME) -proj.generateFont(Mix([rg, bd], 0.35), "%s/Medium/Regular/Lt"%FAMILYNAME) + "%s/Regular/Regular/Rg" % FAMILYNAME) +proj.generateFont(Mix([rg, bd], 0.35), "%s/Medium/Regular/Lt" % FAMILYNAME) proj.generateFont(Mix([rg, bd], RPoint(0.73, 0.73)), - "%s/Bold/Bold/Rg"%FAMILYNAME) + "%s/Bold/Bold/Rg" % FAMILYNAME) proj.generateFont(Mix([rg, bd], RPoint(1.125, 1.0)), - "%s/Black/Regular/Bk"%FAMILYNAME) + "%s/Black/Regular/Bk" % FAMILYNAME) -proj.generateFont(th.font, "%s/Thin Italic/Italic/Th"%FAMILYNAME, +proj.generateFont(th.font, "%s/Thin Italic/Italic/Th" % FAMILYNAME, italic=True, stemWidth=80) -proj.generateFont(Mix([th, rg], 0.45), "%s/Light Italic/Italic/Lt"%FAMILYNAME, +proj.generateFont(Mix([th, rg], 0.45), "%s/Light Italic/Italic/Lt" % FAMILYNAME, italic=True, stemWidth=120) proj.generateFont(Mix([th, rg], RPoint(0.90, 0.92)), - "%s/Italic/Italic/Rg"%FAMILYNAME, italic=True, stemWidth=185) -proj.generateFont(Mix([rg, bd], 0.35), "%s/Medium Italic/Italic/Lt"%FAMILYNAME, + "%s/Italic/Italic/Rg" % FAMILYNAME, + italic=True, stemWidth=185) +proj.generateFont(Mix([rg, bd], 0.35), + "%s/Medium Italic/Italic/Lt" % FAMILYNAME, italic=True, stemWidth=230) proj.generateFont(Mix([rg, bd], RPoint(0.73, 0.73)), - "%s/Bold Italic/Bold Italic/Rg"%FAMILYNAME, + "%s/Bold Italic/Bold Italic/Rg" % FAMILYNAME, italic=True, stemWidth=290) proj.generateFont(Mix([rg, bd], RPoint(1.125, 1.0)), - "%s/Black Italic/Italic/Bk"%FAMILYNAME, + "%s/Black Italic/Italic/Bk" % FAMILYNAME, italic=True, stemWidth=290) # unfortunately some condensed forms (*.cn) of glyphs are not compatible with @@ -127,23 +120,29 @@ cn1 = Master(rg.ffont.addDiff(thcn1.ffont, th.ffont)) bdcn1 = Master(bd.ffont.addDiff(thcn1.ffont, th.ffont)) proj.generateFont(Mix([thcn1, cn1], RPoint(0.45, 0.47)), - "%s Condensed/Light/Regular/Lt"%FAMILYNAME, + "%s Condensed/Light/Regular/Lt" % FAMILYNAME, swapSuffixes=[".cn"]) proj.generateFont(Mix([thcn1, cn1], RPoint(0.9, 0.92)), - "%s Condensed/Regular/Regular/Rg"%FAMILYNAME, + "%s Condensed/Regular/Regular/Rg" % FAMILYNAME, + swapSuffixes=[".cn"]) +proj.generateFont(Mix([cn1, bdcn1], 0.4), + "%s Condensed/Medium/Regular/Lt"%FAMILYNAME, swapSuffixes=[".cn"]) proj.generateFont(Mix([cn1, bdcn1], RPoint(0.75, 0.75)), - "%s Condensed/Bold/Bold/Rg"%FAMILYNAME, + "%s Condensed/Bold/Bold/Rg" % FAMILYNAME, swapSuffixes=[".cn"]) proj.generateFont(Mix([thcn1, cn1], RPoint(0.45, 0.47)), - "%s Condensed/Light Italic/Italic/Lt"%FAMILYNAME, + "%s Condensed/Light Italic/Italic/Lt" % FAMILYNAME, italic=True, swapSuffixes=[".cn"], stemWidth=120) proj.generateFont(Mix([thcn1, cn1], RPoint(0.9, 0.92)), - "%s Condensed/Italic/Italic/Rg"%FAMILYNAME, + "%s Condensed/Italic/Italic/Rg" % FAMILYNAME, italic=True, swapSuffixes=[".cn"], stemWidth=185) +proj.generateFont(Mix([cn1, bdcn1], 0.4), + "%s Condensed/Medium Italic/Italic/Lt"%FAMILYNAME, + italic=True, swapSuffixes=[".cn"], stemWidth=230) proj.generateFont(Mix([cn1, bdcn1], RPoint(0.75, 0.75)), - "%s Condensed/Bold Italic/Bold Italic/Rg"%FAMILYNAME, + "%s Condensed/Bold Italic/Bold Italic/Rg" % FAMILYNAME, italic=True, swapSuffixes=[".cn"], stemWidth=240) proj.generateTTFs() diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index a4e5bac..03defa6 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -18,7 +18,7 @@ import os import sys from booleanOperations import BooleanOperationManager -from cu2qu.rf import fonts_to_quadratic +from cu2qu.ufo import fonts_to_quadratic from fontTools.misc.transform import Transform from robofab.world import OpenFont from ufo2ft import compileOTF, compileTTF @@ -34,23 +34,23 @@ from fontbuild.mix import Mix,Master,narrowFLGlyph class FontProject: - - def __init__(self, basefont, basedir, configfile, thinfont = None): + + def __init__(self, basefont, basedir, configfile): self.basefont = basefont - self.thinfont = thinfont self.basedir = basedir self.config = ConfigParser.RawConfigParser() - self.configfile = self.basedir+"/"+configfile + self.configfile = os.path.join(self.basedir, configfile) self.config.read(self.configfile) - - diacriticList = open(self.basedir + "/" + self.config.get("res","diacriticfile")).readlines() - self.diacriticList = [line.strip() for line in diacriticList if not line.startswith("#")] - self.ot_classes = open(self.basedir + "/" + self.config.get("res","ot_classesfile")).read() - self.ot_kerningclasses = open(self.basedir + "/" + self.config.get("res","ot_kerningclassesfile")).read() - #self.ot_features = open(self.basedir + "/" + self.config.get("res","ot_featuresfile")).read() - adobeGlyphList = open(self.basedir + "/" + self.config.get("res", "agl_glyphlistfile")).readlines() - self.adobeGlyphList = dict([line.split(";") for line in adobeGlyphList if not line.startswith("#")]) - + + self.diacriticList = [ + line.strip() for line in self.openResource("diacriticfile") + if not line.startswith("#")] + self.adobeGlyphList = dict( + line.split(";") for line in self.openResource("agl_glyphlistfile") + if not line.startswith("#")) + self.glyphOrder = self.openResource("glyphorder") + self.thinGlyphOrder = self.openResource("glyphorder_thin") + # map exceptional glyph names in Roboto to names in the AGL roboNames = ( ('Obar', 'Ocenteredtilde'), ('obar', 'obarred'), @@ -64,30 +64,16 @@ class FontProject: self.lessItalic = self.config.get("glyphs","lessitalic").split() self.deleteList = self.config.get("glyphs","delete").split() self.noItalic = self.config.get("glyphs","noitalic").split() - self.buildnumber = self.loadBuildNumber() - + self.buildOTF = False self.compatible = False self.generatedFonts = [] - - - def loadBuildNumber(self): - versionFile = open(self.basedir + "/" + self.config.get("main","buildnumberfile"), "r+") - buildnumber = int(versionFile.read().strip()) - buildnumber = "%05d" %(int(buildnumber) + 1) - print "BuildNumber: %s" %(buildnumber) - versionFile.close() - return buildnumber - - def incrementBuildNumber(self): - if len(self.buildnumber) > 0: - versionFile = open(self.basedir + "/" + self.config.get("main","buildnumberfile"), "r+") - versionFile.seek(0) - versionFile.write(self.buildnumber) - versionFile.truncate() - versionFile.close() - else: - raise Exception("Empty build number") + + def openResource(self, name): + with open(os.path.join( + self.basedir, self.config.get("res", name))) as resourceFile: + resource = resourceFile.read() + return resource.splitlines() def generateOutputPath(self, font, ext): family = font.info.familyName.replace(" ", "") @@ -96,9 +82,9 @@ class FontProject: if not os.path.exists(path): os.makedirs(path) return os.path.join(path, "%s-%s.%s" % (family, style, ext)) - - def generateFont(self, mix, names, italic=False, swapSuffixes=None, stemWidth=185, kern=True): - + + def generateFont(self, mix, names, italic=False, swapSuffixes=None, stemWidth=185): + n = names.split("/") log("---------------------\n%s %s\n----------------------" %(n[0],n[1])) log(">> Mixing masters") @@ -118,7 +104,7 @@ class FontProject: for g in f: i += 1 if i % 10 == 0: print g.name - + if g.name == "uniFFFD": continue @@ -128,11 +114,12 @@ class FontProject: italicizeGlyph(f, g, 9, stemWidth=stemWidth) elif False == (g.name in self.noItalic): italicizeGlyph(f, g, 10, stemWidth=stemWidth) - #elif g.name != ".notdef": - # italicizeGlyph(g, 10, stemWidth=stemWidth) if g.width != 0: g.width += 10 + # set the oblique flag in fsSelection + f.info.openTypeOS2Selection.append(9) + if swapSuffixes != None: for swap in swapSuffixes: swapList = [g.name for g in f if g.name.endswith(swap)] @@ -146,7 +133,7 @@ class FontProject: log(">> Generating glyphs") generateGlyphs(f, self.diacriticList, self.adobeGlyphList) log(">> Copying features") - readFeatureFile(f, self.ot_classes + self.basefont.features.text) + readFeatureFile(f, self.basefont.features.text) log(">> Decomposing") for gname in self.decompose: if f.has_key(gname): @@ -158,10 +145,6 @@ class FontProject: cleanCurves(f) deleteGlyphs(f, self.deleteList) - if kern: - log(">> Generating kern classes") - readFeatureFile(f, self.ot_kerningclasses) - log(">> Generating font files") ufoName = self.generateOutputPath(f, "ufo") f.save(ufoName) @@ -171,7 +154,9 @@ class FontProject: log(">> Generating OTF file") newFont = OpenFont(ufoName) otfName = self.generateOutputPath(f, "otf") - saveOTF(newFont, otfName) + saveOTF( + newFont, otfName, + self.thinGlyphOrder if "Thin" in otfName else self.glyphOrder) def generateTTFs(self): """Build TTF for each font generated since last call to generateTTFs.""" @@ -184,19 +169,19 @@ class FontProject: # fewer control points and look noticeably different max_err = 0.002 if self.compatible: - fonts_to_quadratic(fonts, max_err_em=max_err, dump_stats=True) + fonts_to_quadratic(fonts, max_err_em=max_err, dump_stats=True, reverse_direction=True) else: for font in fonts: - fonts_to_quadratic([font], max_err_em=max_err, dump_stats=True) + fonts_to_quadratic([font], max_err_em=max_err, dump_stats=True, reverse_direction=True) log(">> Generating TTF files") for font in fonts: ttfName = self.generateOutputPath(font, "ttf") log(os.path.basename(ttfName)) - for glyph in font: - for contour in glyph: - contour.reverseContour() - saveOTF(font, ttfName, truetype=True) + saveOTF( + font, ttfName, + self.thinGlyphOrder if "Thin" in ttfName else self.glyphOrder, + truetype=True) def transformGlyphMembers(g, m): @@ -219,6 +204,7 @@ def transformGlyphMembers(g, m): s.Transform(m) #c.scale = s + def swapContours(f,gName1,gName2): try: g1 = f[gName1] @@ -248,7 +234,7 @@ def log(msg): def generateGlyphs(f, glyphNames, glyphList={}): log(">> Generating diacritics") glyphnames = [gname for gname in glyphNames if not gname.startswith("#") and gname != ""] - + for glyphName in glyphNames: generateGlyph(f, glyphName, glyphList) @@ -260,7 +246,7 @@ def cleanCurves(f): # log(">> Mitring sharp corners") # for g in f: # mitreGlyph(g, 3., .7) - + # log(">> Converting curves to quadratic") # for g in f: # glyphCurvesToQuadratic(g) @@ -281,13 +267,16 @@ def removeGlyphOverlap(glyph): manager.union(contours, glyph.getPointPen()) -def saveOTF(font, destFile, truetype=False): +def saveOTF(font, destFile, glyphOrder, truetype=False): """Save a RoboFab font as an OTF binary using ufo2fdk.""" if truetype: - compiler = compileTTF + otf = compileTTF(font, featureCompilerClass=RobotoFeatureCompiler, + kernWriter=RobotoKernWriter, glyphOrder=glyphOrder, + convertCubics=False, + useProductionNames=False) else: - compiler = compileOTF - otf = compiler(font, featureCompilerClass=RobotoFeatureCompiler, - kernWriter=RobotoKernWriter) + otf = compileOTF(font, featureCompilerClass=RobotoFeatureCompiler, + kernWriter=RobotoKernWriter, glyphOrder=glyphOrder, + useProductionNames=False) otf.save(destFile) diff --git a/scripts/lib/fontbuild/generateGlyph.py b/scripts/lib/fontbuild/generateGlyph.py index 5787a37..465f940 100644 --- a/scripts/lib/fontbuild/generateGlyph.py +++ b/scripts/lib/fontbuild/generateGlyph.py @@ -14,91 +14,53 @@ import re -from anchors import alignComponentsToAnchors from string import find +from anchors import alignComponentsToAnchors, getAnchorByName + + def parseComposite(composite): c = composite.split("=") d = c[1].split("/") glyphName = d[0] if len(d) == 1: - offset = [0,0] + offset = [0, 0] else: offset = [int(i) for i in d[1].split(",")] accentString = c[0] accents = accentString.split("+") baseName = accents.pop(0) - accentNames = [i.split(":") for i in accents ] + accentNames = [i.split(":") for i in accents] return (glyphName, baseName, accentNames, offset) def copyMarkAnchors(f, g, srcname, width): - unicode_range = range(0x0030, 0x02B0) + range(0x1E00, 0x1EFF) - anchors = f[srcname].anchors - for anchor in anchors: - if "top_dd" == anchor.name: - g.appendAnchor(anchor.name, (anchor.x + width, anchor.y)) - if "bottom_dd" == anchor.name: + for anchor in f[srcname].anchors: + if anchor.name in ("top_dd", "bottom_dd", "top0315"): g.appendAnchor(anchor.name, (anchor.x + width, anchor.y)) - if "top0315" == anchor.name: - g.appendAnchor(anchor.name, (anchor.x + width, anchor.y)) - if "top" == anchor.name: - if g.unicode == None: - if not g.name.endswith(('.ccmp', '.smcp', '.NAV')): - continue - if False == (g.unicode in unicode_range): - if not g.name.endswith(('.ccmp', '.smcp', '.NAV')): - continue - #if g.unicode > 0x02B0: - # continue - parenttop_present = 0 - for anc in g.anchors: - if anc.name == "parent_top": - parenttop_present = 1 - if 0 == parenttop_present: - g.appendAnchor("parent_top", anchor.position) - - if "bottom" == anchor.name: - if g.unicode == None: - if -1 == find(g.name, ".smcp"): - continue - if False == (g.unicode in unicode_range): - if -1 == find(g.name, ".smcp"): - continue - #if g.unicode > 0x02B0: - # continue - bottom_present = 0 - for anc in g.anchors: - if anc.name == "bottom": - bottom_present = 1 - if 0 == bottom_present: - g.appendAnchor("bottom", anchor.position) - - -# g.appendAnchor("top", anchor.position) - - # if "rhotichook" == anchor.name: - # g.appendAnchor(anchor.name, (anchor.x + width, anchor.y)) - - #print g.anchors - for anchor in g.anchors: - if "top" == anchor.name: - #print g.name, g.anchors - return - - anchor_parent_top = None - for anchor in g.anchors: - if "parent_top" == anchor.name: - anchor_parent_top = anchor - break + if ("top" == anchor.name and + not any(a.name == "parent_top" for a in g.anchors)): + g.appendAnchor("parent_top", anchor.position) + if ("bottom" == anchor.name and + not any(a.name == "bottom" for a in g.anchors)): + g.appendAnchor("bottom", anchor.position) + + if any(a.name == "top" for a in g.anchors): + return + + anchor_parent_top = getAnchorByName(g, "parent_top") if anchor_parent_top is not None: g.appendAnchor("top", anchor_parent_top.position) def generateGlyph(f,gname,glyphList={}): glyphName, baseName, accentNames, offset = parseComposite(gname) + if f.has_key(glyphName): + print('Existing glyph "%s" found in font, ignoring composition rule ' + '"%s"' % (glyphName, gname)) + return if baseName.find("_") != -1: g = f.newGlyph(glyphName) @@ -107,25 +69,21 @@ def generateGlyph(f,gname,glyphList={}): g.width += f[componentName].width setUnicodeValue(g, glyphList) - else: - if not f.has_key(glyphName): - try: - f.compileGlyph(glyphName, baseName, accentNames) - except KeyError as e: - print ("KeyError raised for composition rule '%s', likely %s " - "anchor not found in glyph '%s'" % (gname, e, baseName)) - return - g = f[glyphName] - setUnicodeValue(g, glyphList) - copyMarkAnchors(f, g, baseName, offset[1] + offset[0]) - if offset[0] != 0 or offset[1] != 0: - g.width += offset[1] + offset[0] - g.move((offset[0], 0), anchors=False) - if len(accentNames) > 0: - alignComponentsToAnchors(f, glyphName, baseName, accentNames) - else: - print ("Existing glyph '%s' found in font, ignoring composition " - "rule '%s'" % (glyphName, gname)) + else: + try: + f.compileGlyph(glyphName, baseName, accentNames) + except KeyError as e: + print('KeyError raised for composition rule "%s", likely "%s" ' + 'anchor not found in glyph "%s"' % (gname, e, baseName)) + return + g = f[glyphName] + setUnicodeValue(g, glyphList) + copyMarkAnchors(f, g, baseName, offset[1] + offset[0]) + if len(accentNames) > 0: + alignComponentsToAnchors(f, glyphName, baseName, accentNames) + if offset[0] != 0 or offset[1] != 0: + g.width += offset[1] + offset[0] + g.move((offset[0], 0), anchors=False) def setUnicodeValue(glyph, glyphList): diff --git a/scripts/lib/fontbuild/instanceNames.py b/scripts/lib/fontbuild/instanceNames.py index 890b5a6..dd7cba1 100644 --- a/scripts/lib/fontbuild/instanceNames.py +++ b/scripts/lib/fontbuild/instanceNames.py @@ -66,8 +66,8 @@ class InstanceNames: f.info.openTypeNameManufacturerURL = self.foundry + ".com" f.info.openTypeNameLicense = self.license f.info.openTypeNameLicenseURL = self.licenseURL - f.info.openTypeNameVersion = "%i.%i" %(version,versionMinor) - f.info.openTypeNameUniqueID = "%s:%s:%s" %(self.foundry, self.longfamily, self.year) + f.info.openTypeNameVersion = "Version %i.%i" %(version,versionMinor) + f.info.openTypeNameUniqueID = "%s:%s:%s" %(self.foundry, self.fullname, self.year) # f.info.openTypeNameDescription = "" # f.info.openTypeNameCompatibleFullName = "" # f.info.openTypeNameSampleText = "" diff --git a/scripts/lib/fontbuild/markFeature.py b/scripts/lib/fontbuild/markFeature.py index 395e537..9d091bb 100755 --- a/scripts/lib/fontbuild/markFeature.py +++ b/scripts/lib/fontbuild/markFeature.py @@ -23,26 +23,31 @@ class RobotoFeatureCompiler(FeatureOTFCompiler): def setupAnchorPairs(self): self.anchorPairs = [ - ["top", "_marktop", True, True], - ["bottom", "_markbottom", True, True], - ["top_dd", "_marktop_dd", True, False], - ["bottom_dd", "_markbottom_dd", True, False], - ["rhotichook", "_markrhotichook", False, False], - ["top0315", "_marktop0315", False, False], - ["parent_top", "_markparent_top", False, False], - ["parenthesses.w1", "_markparenthesses.w1", False, False], - ["parenthesses.w2", "_markparenthesses.w2", False, False], - ["parenthesses.w3", "_markparenthesses.w3", False, False]] + ["top", "_marktop"], + ["bottom", "_markbottom"], + ["top_dd", "_marktop_dd"], + ["bottom_dd", "_markbottom_dd"], + ["rhotichook", "_markrhotichook"], + ["top0315", "_marktop0315"], + ["parent_top", "_markparent_top"], + ["parenthesses.w1", "_markparenthesses.w1"], + ["parenthesses.w2", "_markparenthesses.w2"], + ["parenthesses.w3", "_markparenthesses.w3"]] self.mkmkAnchorPairs = [ ["mkmktop", "_marktop"], - ["mkmkbottom_acc", "_markbottom"]] - - def setupAliases(self): - self.aliases = [ - ["a", "uni0430"], ["e", "uni0435"], ["p", "uni0440"], - ["c", "uni0441"], ["x", "uni0445"], ["s", "uni0455"], - ["i", "uni0456"], ["psi", "uni0471"]] + ["mkmkbottom_acc", "_markbottom"], + + # By providing a pair with accent anchor _bottom and no base anchor, + # we designate all glyphs with _bottom as accents (so that they will + # be used as base glyphs for mkmk features) without generating any + # positioning rules actually using this anchor (which is instead + # used to generate composite glyphs). This is all for consistency + # with older roboto versions. + ["", "_bottom"], + ] + + self.ligaAnchorPairs = [] class RobotoKernWriter(KernFeatureWriter): diff --git a/scripts/lib/fontbuild/mix.py b/scripts/lib/fontbuild/mix.py index 519b50d..c958701 100644 --- a/scripts/lib/fontbuild/mix.py +++ b/scripts/lib/fontbuild/mix.py @@ -218,13 +218,12 @@ class FGlyph: class Master: - def __init__(self, font=None, v=0, kernlist=None, overlay=None, - anchorPath=None): + def __init__(self, font=None, v=0, kernlist=None, overlay=None): if isinstance(font, FFont): self.font = None self.ffont = font elif isinstance(font,str): - self.openFont(font,overlay, anchorPath) + self.openFont(font,overlay) elif isinstance(font,Mix): self.font = font else: @@ -243,7 +242,7 @@ class Master: and not k[0] == ""] #TODO implement class based kerning / external kerning file - def openFont(self, path, overlayPath=None, anchorPath=None): + def openFont(self, path, overlayPath=None): self.font = OpenFont(path) for g in self.font: size = len(g) @@ -257,16 +256,6 @@ class Master: for overlayGlyph in overlayFont: font.insertGlyph(overlayGlyph) - # work around a bug with vfb2ufo in which anchors are dropped from - # glyphs containing components and no contours. "anchorPath" should - # point to the output of src/v2/get_dropped_anchors.py - if anchorPath: - anchorData = json.load(open(anchorPath)) - for glyphName, anchors in anchorData.items(): - glyph = self.font[glyphName] - for name, (x, y) in anchors.items(): - glyph.appendAnchor(str(name), (x, y)) - self.ffont = FFont(self.font) @@ -345,14 +334,24 @@ def interpolate(a,b,v,e=0): qe = (b-a)*v*v*v + a #cubic easing le = a+(b-a)*v # linear easing return le + (qe-le) * e - + def interpolateKerns(kA, kB, v): - kerns = {} - for pair in kA.keys(): - matchedKern = kB.get(pair) - # if matchedkern == None: - # matchedkern = Kern(kA) - # matchedkern.value = 0 - if matchedKern != None: - kerns[pair] = interpolate(kA[pair], matchedKern, v.x) - return kerns + # to yield correct kerning for Roboto output, we must emulate the behavior + # of old versions of this code; namely, take the kerning values of the first + # master instead of actually interpolating. + # old code: + # https://github.com/google/roboto/blob/7f083ac31241cc86d019ea6227fa508b9fcf39a6/scripts/lib/fontbuild/mix.py + # bug: + # https://github.com/google/roboto/issues/213 + + #kerns = {} + #for pair, val in kA.items(): + # kerns[pair] = interpolate(val, kB.get(pair, 0), v.x) + #for pair, val in kB.items(): + # lerped_val = interpolate(val, kA.get(pair, 0), 1 - v.x) + # if pair in kerns: + # assert abs(kerns[pair] - lerped_val) < 1e-6 + # else: + # kerns[pair] = lerped_val + #return kerns + return dict(kA) diff --git a/scripts/render.sh b/scripts/render.sh index 2266b2a..9e2862b 100755 --- a/scripts/render.sh +++ b/scripts/render.sh @@ -16,7 +16,7 @@ HARFBUZZ=$HOME/harfbuzz -FONTDIR=$(dirname $0)/../hinted +FONTDIR=$(dirname $0)/../src/hinted input_file=$1 diff --git a/scripts/roboto_data.py b/scripts/roboto_data.py index a9a947a..eaeaaea 100644 --- a/scripts/roboto_data.py +++ b/scripts/roboto_data.py @@ -14,16 +14,18 @@ """General module for Roboto-specific data and methods.""" +import ConfigParser import os -from os import path import re -def get_build_number(): - """Returns the build number as a five-digit string.""" - build_number_txt = path.join( - path.dirname(__file__), os.pardir, 'res', 'buildnumber.txt') - build_number = open(build_number_txt).read().strip() - assert re.match('[0-9]{5}', build_number) - return build_number +def get_version_number(): + """Returns the version number as a string.""" + config_parser = ConfigParser.RawConfigParser() + config_file = os.path.join( + os.path.dirname(__file__), os.pardir, 'res', 'roboto.cfg') + config_parser.read(config_file) + version_number = config_parser.get('main', 'version') + assert re.match(r'[0-9]+\.[0-9]{3}', version_number) + return version_number diff --git a/scripts/run_android_tests.py b/scripts/run_android_tests.py index f6a1f46..9bf52e7 100755 --- a/scripts/run_android_tests.py +++ b/scripts/run_android_tests.py @@ -24,7 +24,11 @@ import run_general_tests FONTS = font_tests.load_fonts( ['out/android/*.ttf'], - expected_count=18) + expected_count=20) + + +class TestItalicAngle(run_general_tests.TestItalicAngle): + loaded_fonts = FONTS class TestMetaInfo(run_general_tests.TestMetaInfo): @@ -35,6 +39,18 @@ class TestMetaInfo(run_general_tests.TestMetaInfo): loaded_fonts = FONTS mark_heavier_as_bold = True + def test_glyphs_dont_round_to_grid(self): + """Bug: https://github.com/google/roboto/issues/153""" + + for font in self.fonts: + glyph_set = font.getGlyphSet() + + # only concerned with this glyph for now, but maybe more later + for name in ['ellipsis']: + glyph = glyph_set[name]._glyph + for component in glyph.components: + self.assertFalse(component.flags & (1 << 2)) + class TestNames(run_general_tests.TestNames): """Bugs: @@ -42,22 +58,25 @@ class TestNames(run_general_tests.TestNames): """ loaded_fonts = FONTS - mark_heavier_as_bold = True class TestVerticalMetrics(font_tests.TestVerticalMetrics): loaded_fonts = FONTS - test_glyphs_ymin_ymax = None - test_hhea_table_metrics = None test_os2_metrics = None + # tests yMin and yMax to be equal to Roboto v1 values + # android requires this, and web fonts expect this expected_head_yMin = -555 expected_head_yMax = 2163 + # test ascent, descent, and lineGap to be equal to Roboto v1 values + expected_hhea_descent = -500 + expected_hhea_ascent = 1900 + expected_hhea_lineGap = 0 + class TestDigitWidths(font_tests.TestDigitWidths): loaded_fonts = FONTS - test_superscript_digits = None class TestCharacterCoverage(font_tests.TestCharacterCoverage): @@ -76,7 +95,7 @@ class TestCharacterCoverage(font_tests.TestCharacterCoverage): ) - include # don't exclude legacy PUA -class TestSpacingMarks(font_tests.TestSpacingMarks): +class TestLigatures(run_general_tests.TestLigatures): loaded_fonts = FONTS diff --git a/scripts/run_exhaustive_tests.py b/scripts/run_exhaustive_tests.py index 10dd2d7..5c94dca 100755 --- a/scripts/run_exhaustive_tests.py +++ b/scripts/run_exhaustive_tests.py @@ -21,7 +21,7 @@ from nototools.unittests import font_tests FONTS = font_tests.load_fonts( ['out/RobotoTTF/*.ttf', 'out/RobotoCondensedTTF/*.ttf'], - expected_count=18) + expected_count=20) class TestSpacingMarks(font_tests.TestSpacingMarks): diff --git a/scripts/run_general_tests.py b/scripts/run_general_tests.py index 494651d..fbae2cf 100755 --- a/scripts/run_general_tests.py +++ b/scripts/run_general_tests.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# coding=UTF-8 # # Copyright 2015 Google Inc. All Rights Reserved. # @@ -25,18 +26,14 @@ import roboto_data FONTS = font_tests.load_fonts( ['out/RobotoTTF/*.ttf', 'out/RobotoCondensedTTF/*.ttf'], - expected_count=18) - -UFOS = font_tests.load_fonts( - ['out/RobotoUFO/*.ufo', 'out/RobotoCondensedUFO/*.ufo'], - expected_count=18, - font_class=OpenFont) + expected_count=20) UFO_MASTERS = font_tests.load_fonts( ['src/v2/*.ufo'], expected_count=3, font_class=OpenFont) + class TestItalicAngle(font_tests.TestItalicAngle): loaded_fonts = FONTS expected_italic_angle = -12.0 @@ -51,10 +48,10 @@ class TestMetaInfo(font_tests.TestMetaInfo): loaded_fonts = FONTS mark_heavier_as_bold = False + mark_italic_as_oblique = True test_us_weight = None - #expected_version = '2.' + roboto_data.get_build_number() - test_version_numbers = None + expected_version = roboto_data.get_version_number() # fsType of 0 marks the font free for installation, embedding, etc. expected_os2_fsType = 0 @@ -72,7 +69,7 @@ class TestNames(font_tests.TestNames): expected_copyright = 'Copyright 2011 Google Inc. All Rights Reserved.' def expected_unique_id(self, family, style): - return 'Google:%s:2015' % family + return 'Google:%s %s:2016' % (family, style) class TestDigitWidths(font_tests.TestDigitWidths): @@ -94,10 +91,24 @@ class TestCharacterCoverage(font_tests.TestCharacterCoverage): class TestLigatures(font_tests.TestLigatures): loaded_fonts = FONTS + active = ( + (None, ('fi', 'fl', 'ffi', 'ffl')), + ('--language=FRA', ('fi', 'fl', 'ffi', 'ffl')), + ('--language=TRK', ('fl', 'ffl')), + ('--features=dlig', ('ff', 'st', u'ſt')), + ) + inactive = ( + (None, ('ff', 'st', u'ſt')), + ('--language=TRK', ('fi', 'ffi')), + ('--script=arab', ('fi', 'fl', 'ffi', 'ffl')), + ) class TestFeatures(font_tests.TestFeatures): loaded_fonts = FONTS + smcp_reqs_path = 'res/smcp_requirements.txt' + c2sc_reqs_path = 'res/c2sc_requirements.txt' + unic_reqs_path = 'res/unic_requirements.txt' class TestVerticalMetrics(font_tests.TestVerticalMetrics): @@ -106,10 +117,29 @@ class TestVerticalMetrics(font_tests.TestVerticalMetrics): test_hhea_table_metrics = None test_os2_metrics = None + # tests yMin and yMax to be equal to Roboto v1 values + # android requires this, and web fonts expect this expected_head_yMin = -555 expected_head_yMax = 2163 +class TestGlyphBounds(font_tests.TestGlyphBounds): + loaded_fonts = FONTS + + should_exceed = ( + (('chi',), (None, 0, None, None), 0, 'is it an alias of x?'), + ) + + should_not_exceed = ( + (('Epsilontonos', 'Etatonos', 'Iotatonos', 'Upsilontonos'), + (-150, None, None, None), 0.4, + 'may be susceptible to aggressive clipping'), + (('uni1F1B', 'uni1F2B', 'uni1F3B', 'uni1F5B', 'uni1F9B'), + (-550, None, None, None), 0.1, + 'may be susceptible to aggressive clipping'), + ) + + class TestGlyphAreas(font_tests.TestGlyphAreas): master_weights_to_test = ['Thin', 'Bold'] instance_weights_to_test = ['Thin', 'Regular', 'Bold'] diff --git a/scripts/run_web_tests.py b/scripts/run_web_tests.py index 5d3fd34..160510e 100755 --- a/scripts/run_web_tests.py +++ b/scripts/run_web_tests.py @@ -17,22 +17,23 @@ """Test assumptions that web fonts rely on.""" import unittest - -from nototools import font_data from nototools.unittests import font_tests +import run_general_tests + + FONTS = font_tests.load_fonts( ['out/web/*.ttf'], expected_count=18) -class TestItalicAngle(font_tests.TestItalicAngle): + +class TestItalicAngle(run_general_tests.TestItalicAngle): loaded_fonts = FONTS - expected_italic_angle = -12.0 class TestMetaInfo(font_tests.TestMetaInfo): loaded_fonts = FONTS - mark_heavier_as_bold = True + mark_heavier_as_bold = False # Since different font files are hinted at different times, the actual # outlines differ slightly. So we are keeping the version numbers as a hint. @@ -43,18 +44,18 @@ class TestMetaInfo(font_tests.TestMetaInfo): expected_os2_achVendID = 'GOOG' -class TestNames(font_tests.TestNames): +class TestNames(run_general_tests.TestNames): """Bugs: https://github.com/google/roboto/issues/37 """ loaded_fonts = FONTS - family_name = 'Roboto' - mark_heavier_as_bold = True - expected_copyright = 'Copyright 2011 Google Inc. All Rights Reserved.' def expected_unique_id(self, family, style): - return family + ' ' + style + expected = family + if style != 'Regular': + expected += ' ' + style + return expected class TestDigitWidths(font_tests.TestDigitWidths): @@ -79,13 +80,17 @@ class TestCharacterCoverage(font_tests.TestCharacterCoverage): class TestVerticalMetrics(font_tests.TestVerticalMetrics): loaded_fonts = FONTS + # tests yMin and yMax to be equal to Roboto v1 values + # android requires this, and web fonts expect this expected_head_yMin = -555 expected_head_yMax = 2163 + # test ascent, descent, and lineGap to be equal to Roboto v1 values expected_hhea_descent = -500 expected_hhea_ascent = 1900 expected_hhea_lineGap = 0 + # test OS/2 vertical metrics to be equal to the old values expected_os2_sTypoDescender = -512 expected_os2_sTypoAscender = 1536 expected_os2_sTypoLineGap = 102 @@ -93,10 +98,19 @@ class TestVerticalMetrics(font_tests.TestVerticalMetrics): expected_os2_usWinAscent = 1946 -class TestLigatures(font_tests.TestLigatures): +class TestLigatures(run_general_tests.TestLigatures): loaded_fonts = FONTS +class TestGlyphBounds(run_general_tests.TestGlyphBounds): + loaded_fonts = FONTS + + # a bug in which monotonic and polytonic glyphs extend too far left is + # fixed in the unhinted output, but still present in the hinted binaries and + # not fixed by the web target + should_not_exceed = () + + class TestHints(font_tests.TestHints): loaded_fonts = FONTS diff --git a/scripts/temporary_touchups.py b/scripts/temporary_touchups.py index 8953b64..a20a938 100644 --- a/scripts/temporary_touchups.py +++ b/scripts/temporary_touchups.py @@ -20,30 +20,30 @@ from nototools import noto_fonts import roboto_data -def apply_temporary_fixes(font): +def apply_temporary_fixes(font, is_for_cros=False, is_for_web=False): """Apply some temporary fixes.""" # Fix usWeight: font_name = font_data.font_name(font) weight = noto_fonts.parse_weight(font_name) weight_number = noto_fonts.WEIGHTS[weight] + # Chrome OS wants Thin to have usWeightClass=100 + if is_for_cros and weight == 'Thin': + weight_number = 100 font['OS/2'].usWeightClass = weight_number - # Set ascent, descent, and lineGap values to Android K values - hhea = font['hhea'] - hhea.ascent = 1900 - hhea.descent = -500 - hhea.lineGap = 0 - - # Copyright message - font_data.set_name_record( - font, 0, 'Copyright 2011 Google Inc. All Rights Reserved.') - + # Set bold bits for Black (macStyle bit 0, fsSelection bit 5) + if is_for_web is False: + name_records = font_data.get_name_records(font) + family_name = name_records[1] + if family_name.endswith('Black'): + font['head'].macStyle |= (1 << 0) + font['OS/2'].fsSelection |= (1 << 5) + font['OS/2'].fsSelection &= ~(1 << 6) def update_version_and_revision(font): - """Update version and revision numbers from buildnumber.txt.""" - build_number = roboto_data.get_build_number() - version_number = '2.' + build_number + """Update version and revision numbers.""" + + version_number = roboto_data.get_version_number() version_record = 'Version %s; %d' % (version_number, date.today().year) font_data.set_name_record(font, 5, version_record) font['head'].fontRevision = float(version_number) - diff --git a/scripts/touchup_for_android.py b/scripts/touchup_for_android.py index e13adea..9855717 100755 --- a/scripts/touchup_for_android.py +++ b/scripts/touchup_for_android.py @@ -16,44 +16,16 @@ """Post-build changes for Roboto for Android.""" -import os -from os import path import sys from fontTools import ttLib from nototools import font_data - -def apply_temporary_fixes(font): - """Apply some temporary fixes. - """ - # Fix version number from buildnumber.txt - from datetime import date - - build_number_txt = path.join( - path.dirname(__file__), os.pardir, 'res', 'buildnumber.txt') - build_number = open(build_number_txt).read().strip() - - version_record = 'Version 2.%s; %d' % (build_number, date.today().year) - - for record in font['name'].names: - if record.nameID == 5: - if record.platformID == 1 and record.platEncID == 0: # MacRoman - record.string = version_record - elif record.platformID == 3 and record.platEncID == 1: - # Windows UCS-2 - record.string = version_record.encode('UTF-16BE') - else: - assert False +import temporary_touchups def apply_android_specific_fixes(font): """Apply fixes needed for Android.""" - # Set ascent, descent, and lineGap values to Android K values - hhea = font['hhea'] - hhea.ascent = 1900 - hhea.descent = -500 - hhea.lineGap = 0 # Remove combining keycap and the arrows from the cmap table: # https://github.com/google/roboto/issues/99 @@ -68,23 +40,20 @@ def apply_android_specific_fixes(font): if table in font: del font[table] - # Set bold bits for Black (macStyle bit 0, fsSelection bit 5, subfamily) - name_records = font_data.get_name_records(font) - family_name = name_records[1] - subfam_name = name_records[2] - if family_name.endswith('Black'): - font['head'].macStyle |= (1 << 0) - font['OS/2'].fsSelection |= (1 << 5) - font['OS/2'].fsSelection &= ~(1 << 6) - new_subfam_name = ( - ('Bold ' + subfam_name) if subfam_name != 'Regular' else 'Bold') - font_data.set_name_record(font, 2, new_subfam_name) + # turn off round-to-grid flags in certain problem components + # https://github.com/google/roboto/issues/153 + glyph_set = font.getGlyphSet() + ellipsis = glyph_set['ellipsis']._glyph + for component in ellipsis.components: + component.flags &= ~(1 << 2) def correct_font(source_font_name, target_font_name): """Corrects metrics and other meta information.""" + font = ttLib.TTFont(source_font_name) - apply_temporary_fixes(font) + temporary_touchups.apply_temporary_fixes(font) + temporary_touchups.update_version_and_revision(font) apply_android_specific_fixes(font) font.save(target_font_name) diff --git a/scripts/touchup_for_cros.py b/scripts/touchup_for_cros.py new file mode 100755 index 0000000..0219f03 --- /dev/null +++ b/scripts/touchup_for_cros.py @@ -0,0 +1,60 @@ +#!/usr/bin/python +# +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Post-build changes for Roboto to deploy on Google Chrome/Chromium OS""" + +import sys + +from fontTools import ttLib +from nototools import font_data +from touchup_for_web import apply_web_cros_common_fixes + +import temporary_touchups + +def drop_non_windows_name_records(font): + """Drop name records whose (PID,EID,Lang) != (3,1,0x409)""" + names = font['name'].names + records_to_drop = set() + for record_number, record in enumerate(names): + name_ids = (record.platformID, record.platEncID, record.langID) + if name_ids != (3, 1, 0x409): + records_to_drop.add(record_number) + + # Taken from nototools/font_data.py + if records_to_drop: + font['name'].names = [ + record for record_number, record in enumerate(names) + if record_number not in records_to_drop] + +def correct_font(source_name, unhinted_name, target_font_name, family_name): + """Corrects metrics and other meta information.""" + + font = ttLib.TTFont(source_name) + unhinted = ttLib.TTFont(unhinted_name) + + apply_web_cros_common_fixes(font, unhinted, family_name) + temporary_touchups.apply_temporary_fixes(font, is_for_cros=True) + temporary_touchups.update_version_and_revision(font) + drop_non_windows_name_records(font) + font.save(target_font_name) + +def main(argv): + """Correct the font specified in the command line.""" + correct_font(*argv[1:]) + + +if __name__ == "__main__": + main(sys.argv) diff --git a/scripts/touchup_for_web.py b/scripts/touchup_for_web.py index 7879d9e..108807a 100755 --- a/scripts/touchup_for_web.py +++ b/scripts/touchup_for_web.py @@ -24,9 +24,14 @@ from nototools import font_data import temporary_touchups -def apply_web_specific_fixes(font, family_name): +def apply_web_specific_fixes(font, unhinted, family_name): """Apply fixes needed for web fonts.""" - # Set OS/2 table values to old values + + # set vertical metrics to old values + hhea = font['hhea'] + hhea.ascent = 1900 + hhea.descent = -500 + os2 = font['OS/2'] os2.sTypoAscender = 1536 os2.sTypoDescender = -512 @@ -34,6 +39,12 @@ def apply_web_specific_fixes(font, family_name): os2.usWinAscent = 1946 os2.usWinDescent = 512 + # correct anything else needed for both web and Chrome OS + apply_web_cros_common_fixes(font, unhinted, family_name) + + +def apply_web_cros_common_fixes(font, unhinted, family_name): + """Apply fixes needed for web and CrOS targets""" subfamily_name = font_data.get_name_records(font)[2].encode('ASCII') assert(subfamily_name in ['Thin', 'Thin Italic', @@ -45,7 +56,9 @@ def apply_web_specific_fixes(font, family_name): if 'Condensed' in font_data.get_name_records(font)[1]: family_name += ' Condensed' - full_name = family_name + ' ' + subfamily_name + full_name = family_name + if subfamily_name != 'Regular': + full_name += ' ' + subfamily_name # Family, subfamily names font_data.set_name_record(font, 16, family_name) @@ -54,8 +67,15 @@ def apply_web_specific_fixes(font, family_name): font_data.set_name_record(font, 1, family_name) else: weight = subfamily_name.split()[0] - font_data.set_name_record(font, 1, '%s %s' % (family_name, weight)) - font_data.set_name_record(font, 2, style_map[macStyle]) + new_family_name = family_name + if weight != 'Regular': + new_family_name += ' ' + weight + font_data.set_name_record(font, 1, new_family_name) + + # all weights outside regular and bold should only have subfamily + # "Regular" or "Italic" + italic = subfamily_name.endswith('Italic') + font_data.set_name_record(font, 2, style_map[italic << 1]) # Unique identifier and full name font_data.set_name_record(font, 3, full_name) @@ -66,18 +86,51 @@ def apply_web_specific_fixes(font, family_name): font_data.set_name_record( font, 6, (family_name+'-'+subfamily_name).replace(' ', '')) + # Copyright message + font_data.set_name_record( + font, 0, 'Copyright 2011 Google Inc. All Rights Reserved.') + + # hotpatch glyphs by swapping + # https://github.com/google/roboto/issues/18 + glyf = font['glyf'] + glyf['chi'], glyf['chi.alt'] = glyf['chi.alt'], glyf['chi'] -def correct_font(source_font_name, target_font_name, family_name): + # make glyph orders consistent for feature copying + # https://github.com/google/roboto/issues/71 + glyph_order = font.getGlyphOrder() + for i, glyph_name in enumerate(glyph_order): + if glyph_name.endswith('.lnum'): + new_name = glyph_name.replace('.lnum', '.pnum') + glyph_order[i] = new_name + font['glyf'][new_name] = font['glyf'][glyph_name] + + # append old name to glyph order so del succeeds + glyph_order.append(glyph_name) + del font['glyf'][glyph_name] + + # copy features from unhinted + # https://github.com/google/roboto/pull/163 + for table in ['GDEF', 'GPOS', 'GSUB']: + font[table] = unhinted[table] + + +def correct_font(source_name, unhinted_name, target_font_name, family_name): """Corrects metrics and other meta information.""" - font = ttLib.TTFont(source_font_name) - temporary_touchups.apply_temporary_fixes(font) - apply_web_specific_fixes(font, family_name) + + font = ttLib.TTFont(source_name) + unhinted = ttLib.TTFont(unhinted_name) + + # apply web-specific fixes before shared, so that sub/family names are + # correct for black weights and their bold bits will be set + apply_web_specific_fixes(font, unhinted, family_name) + temporary_touchups.apply_temporary_fixes(font, is_for_web=True) + temporary_touchups.update_version_and_revision(font) font.save(target_font_name) def main(argv): """Correct the font specified in the command line.""" - correct_font(argv[1], argv[2], argv[3]) + correct_font(*argv[1:]) if __name__ == "__main__": -- cgit v1.2.3