From b0710b829b18be1fa2cb4438b88b12aedce51821 Mon Sep 17 00:00:00 2001 From: Miguel Sousa Date: Mon, 1 Apr 2019 14:14:45 -0700 Subject: [PATCH 1/3] [fontBuilder] Enable making CFF2 fonts with 'post' table format 2 Before this change all OTFs wound up with 'post' table format 3 --- Lib/fontTools/fontBuilder.py | 3 +- Tests/fontBuilder/data/test_var.otf.ttx | 40 +++++++---- Tests/fontBuilder/fontBuilder_test.py | 92 +++++++++++++++++-------- 3 files changed, 93 insertions(+), 42 deletions(-) diff --git a/Lib/fontTools/fontBuilder.py b/Lib/fontTools/fontBuilder.py index 8854c1644..04e98a1b2 100644 --- a/Lib/fontTools/fontBuilder.py +++ b/Lib/fontTools/fontBuilder.py @@ -690,8 +690,9 @@ class FontBuilder(object): """Create a new `post` table and initialize it with default values, which can be overridden by keyword arguments. """ + isCFF2 = 'CFF2' in self.font postTable = self._initTableWithValues("post", _postDefaults, values) - if self.isTTF and keepGlyphNames: + if (self.isTTF or isCFF2) and keepGlyphNames: postTable.formatType = 2.0 postTable.extraNames = [] postTable.mapping = {} diff --git a/Tests/fontBuilder/data/test_var.otf.ttx b/Tests/fontBuilder/data/test_var.otf.ttx index c9465d23f..960294114 100644 --- a/Tests/fontBuilder/data/test_var.otf.ttx +++ b/Tests/fontBuilder/data/test_var.otf.ttx @@ -1,10 +1,10 @@ - + - + @@ -13,12 +13,12 @@ - + - - + + @@ -110,9 +110,9 @@ + - @@ -179,7 +179,7 @@ - + @@ -188,6 +188,18 @@ + + + + + + @@ -212,6 +224,13 @@ 67 66 33 67 67 hvcurveto -900 vlineto + + 100 100 rmoveto + 900 vlineto + -67 67 66 -33 67 hhcurveto + 67 66 33 67 67 hvcurveto + -900 vlineto + 100 100 rmoveto 900 vlineto @@ -229,13 +248,6 @@ -400 -400 1 blend hlineto - - 100 100 rmoveto - 900 vlineto - -67 67 66 -33 67 hhcurveto - 67 66 33 67 67 hvcurveto - -900 vlineto - diff --git a/Tests/fontBuilder/fontBuilder_test.py b/Tests/fontBuilder/fontBuilder_test.py index 97d7cb6a7..9bd571cc6 100644 --- a/Tests/fontBuilder/fontBuilder_test.py +++ b/Tests/fontBuilder/fontBuilder_test.py @@ -2,14 +2,13 @@ from __future__ import print_function, division, absolute_import from __future__ import unicode_literals import os -import shutil +import pytest import re from fontTools.ttLib import TTFont from fontTools.pens.ttGlyphPen import TTGlyphPen from fontTools.pens.t2CharStringPen import T2CharStringPen from fontTools.fontBuilder import FontBuilder from fontTools.ttLib.tables.TupleVariation import TupleVariation -from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates from fontTools.misc.psCharStrings import T2CharString @@ -53,6 +52,43 @@ def _setupFontBuilder(isTTF, unitsPerEm=1024): return fb, advanceWidths, nameStrings +def _setupFontBuilderFvar(fb): + assert 'name' in fb.font, 'Must run setupNameTable() first.' + + axes = [ + ('TEST', 0, 0, 100, "Test Axis"), + ] + instances = [ + dict(location=dict(TEST=0), stylename="TotallyNormal"), + dict(location=dict(TEST=100), stylename="TotallyTested"), + ] + fb.setupFvar(axes, instances) + + return fb + + +def _setupFontBuilderCFF2(fb): + assert 'fvar' in fb.font, 'Must run _setupFontBuilderFvar() first.' + + pen = T2CharStringPen(None, None, CFF2=True) + drawTestGlyph(pen) + charString = pen.getCharString() + + program = [ + 200, 200, -200, -200, 2, "blend", "rmoveto", + 400, 400, 1, "blend", "hlineto", + 400, 400, 1, "blend", "vlineto", + -400, -400, 1, "blend", "hlineto" + ] + charStringVariable = T2CharString(program=program) + + charStrings = {".notdef": charString, "A": charString, + "a": charStringVariable, ".null": charString} + fb.setupCFF2(charStrings, regions=[{"TEST": (0, 1, 1)}]) + + return fb + + def _verifyOutput(outPath, tables=None): f = TTFont(outPath) f.saveXML(outPath + ".ttx", tables=tables) @@ -191,32 +227,9 @@ def test_build_cff2(tmpdir): outPath = os.path.join(str(tmpdir), "test_var.otf") fb, advanceWidths, nameStrings = _setupFontBuilder(False, 1000) - fb.setupNameTable(nameStrings) - - axes = [ - ('TEST', 0, 0, 100, "Test Axis"), - ] - instances = [ - dict(location=dict(TEST=0), stylename="TotallyNormal"), - dict(location=dict(TEST=100), stylename="TotallyTested"), - ] - fb.setupFvar(axes, instances) - - pen = T2CharStringPen(None, None, CFF2=True) - drawTestGlyph(pen) - charString = pen.getCharString() - - program = [ - 200, 200, -200, -200, 2, "blend", "rmoveto", - 400, 400, 1, "blend", "hlineto", - 400, 400, 1, "blend", "vlineto", - -400, -400, 1, "blend", "hlineto" - ] - charStringVariable = T2CharString(program=program) - - charStrings = {".notdef": charString, "A": charString, "a": charStringVariable, ".null": charString} - fb.setupCFF2(charStrings, regions=[{"TEST": (0, 1, 1)}]) + fb = _setupFontBuilderFvar(fb) + fb = _setupFontBuilderCFF2(fb) metrics = {gn: (advanceWidth, 0) for gn, advanceWidth in advanceWidths.items()} fb.setupHorizontalMetrics(metrics) @@ -246,6 +259,31 @@ def test_setupNameTable_no_windows(): assert not any(n for n in fb.font["name"].names if n.platformID == 3) +@pytest.mark.parametrize('is_ttf, keep_glyph_names, make_cff2, post_format', [ + (True, True, False, 2), # TTF with post table format 2.0 + (True, False, False, 3), # TTF with post table format 3.0 + (False, True, False, 3), # CFF with post table format 3.0 + (False, False, False, 3), # CFF with post table format 3.0 + (False, True, True, 2), # CFF2 with post table format 2.0 + (False, False, True, 3), # CFF2 with post table format 3.0 +]) +def test_setupPost(is_ttf, keep_glyph_names, make_cff2, post_format): + fb, _, nameStrings = _setupFontBuilder(is_ttf) + + if make_cff2: + fb.setupNameTable(nameStrings) + fb = _setupFontBuilderCFF2(_setupFontBuilderFvar(fb)) + + if keep_glyph_names: + fb.setupPost() + else: + fb.setupPost(keepGlyphNames=keep_glyph_names) + + assert fb.isTTF is is_ttf + assert ('CFF2' in fb.font) is make_cff2 + assert fb.font["post"].formatType == post_format + + def test_unicodeVariationSequences(tmpdir): familyName = "UVSTestFont" styleName = "Regular" From 86cea23de3d64cc2b9223468710179530adcd09a Mon Sep 17 00:00:00 2001 From: Miguel Sousa Date: Mon, 1 Apr 2019 21:25:27 -0700 Subject: [PATCH 2/3] Un-hardcode the CFF glyph's left side bearing --- Lib/fontTools/fontBuilder.py | 3 ++- Tests/fontBuilder/fontBuilder_test.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/fontTools/fontBuilder.py b/Lib/fontTools/fontBuilder.py index 04e98a1b2..18f6d4371 100644 --- a/Lib/fontTools/fontBuilder.py +++ b/Lib/fontTools/fontBuilder.py @@ -100,9 +100,10 @@ charString = pen.getCharString() charStrings = {".notdef": charString, "A": charString, "a": charString, ".null": charString} fb.setupCFF(nameStrings['psName'], {"FullName": nameStrings['psName']}, charStrings, {}) +lsb = {gn: cs.calcBounds(None)[0] for gn, cs in charStrings.items()} metrics = {} for gn, advanceWidth in advanceWidths.items(): - metrics[gn] = (advanceWidth, 100) # XXX lsb from glyph + metrics[gn] = (advanceWidth, lsb[gn]) fb.setupHorizontalMetrics(metrics) fb.setupHorizontalHeader(ascent=824, descent=200) diff --git a/Tests/fontBuilder/fontBuilder_test.py b/Tests/fontBuilder/fontBuilder_test.py index 9bd571cc6..641f4bd73 100644 --- a/Tests/fontBuilder/fontBuilder_test.py +++ b/Tests/fontBuilder/fontBuilder_test.py @@ -135,9 +135,11 @@ def test_build_otf(tmpdir): charString = pen.getCharString() charStrings = {".notdef": charString, "A": charString, "a": charString, ".null": charString} fb.setupCFF(nameStrings['psName'], {"FullName": nameStrings['psName']}, charStrings, {}) + + lsb = {gn: cs.calcBounds(None)[0] for gn, cs in charStrings.items()} metrics = {} for gn, advanceWidth in advanceWidths.items(): - metrics[gn] = (advanceWidth, 100) # XXX lsb from glyph + metrics[gn] = (advanceWidth, lsb[gn]) fb.setupHorizontalMetrics(metrics) fb.setupHorizontalHeader(ascent=824, descent=200) From 2c54bf7910e2663bcc61d4d1cc8ba97089703d97 Mon Sep 17 00:00:00 2001 From: Miguel Sousa Date: Mon, 1 Apr 2019 21:26:07 -0700 Subject: [PATCH 3/3] Use existing method --- Tests/fontBuilder/fontBuilder_test.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Tests/fontBuilder/fontBuilder_test.py b/Tests/fontBuilder/fontBuilder_test.py index 641f4bd73..7d73b87ee 100644 --- a/Tests/fontBuilder/fontBuilder_test.py +++ b/Tests/fontBuilder/fontBuilder_test.py @@ -156,17 +156,7 @@ def test_build_otf(tmpdir): def test_build_var(tmpdir): outPath = os.path.join(str(tmpdir), "test_var.ttf") - fb = FontBuilder(1024, isTTF=True) - fb.setupGlyphOrder([".notdef", ".null", "A", "a"]) - fb.setupCharacterMap({65: "A", 97: "a"}) - - advanceWidths = {".notdef": 600, "A": 600, "a": 600, ".null": 600} - - familyName = "HelloTestFont" - styleName = "TotallyNormal" - nameStrings = dict(familyName=dict(en="HelloTestFont", nl="HalloTestFont"), - styleName=dict(en="TotallyNormal", nl="TotaalNormaal")) - nameStrings['psName'] = familyName + "-" + styleName + fb, advanceWidths, nameStrings = _setupFontBuilder(True) pen = TTGlyphPen(None) pen.moveTo((100, 0))