Skip to content

Commit

Permalink
{v,h}mtx: allow to compile/decompile even without {v,h}hhea table
Browse files Browse the repository at this point in the history
when no horizontal/vertical header table is present, we assume numberOfHMetrics == maxp.numGlyphs.
This allows to compile/decompile incomplete fonts, only containing head, maxp, hmtx, loca and glyf (or CFF),
that is the bare minimum to temporarily store glyph outline and metrics data for use with sparse/intermediate
master TTFs in varLib.
See googlefonts/ufo2ft#308
  • Loading branch information
anthrotype committed Jan 14, 2019
1 parent 36da84d commit 8350332
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 14 deletions.
39 changes: 25 additions & 14 deletions Lib/fontTools/ttLib/tables/_h_m_t_x.py
Expand Up @@ -23,7 +23,11 @@ class table__h_m_t_x(DefaultTable.DefaultTable):

def decompile(self, data, ttFont):
numGlyphs = ttFont['maxp'].numGlyphs
numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName))
headerTable = ttFont.get(self.headerTag)
if headerTable is not None:
numberOfMetrics = int(getattr(headerTable, self.numberOfMetricsName))
else:
numberOfMetrics = numGlyphs
if numberOfMetrics > numGlyphs:
log.warning("The %s.%s exceeds the maxp.numGlyphs" % (
self.headerTag, self.numberOfMetricsName))
Expand Down Expand Up @@ -69,19 +73,26 @@ def compile(self, ttFont):
glyphName, self.advanceName))
hasNegativeAdvances = True
metrics.append([advanceWidth, sideBearing])
lastAdvance = metrics[-1][0]
lastIndex = len(metrics)
while metrics[lastIndex-2][0] == lastAdvance:
lastIndex -= 1
if lastIndex <= 1:
# all advances are equal
lastIndex = 1
break
additionalMetrics = metrics[lastIndex:]
additionalMetrics = [otRound(sb) for _, sb in additionalMetrics]
metrics = metrics[:lastIndex]
numberOfMetrics = len(metrics)
setattr(ttFont[self.headerTag], self.numberOfMetricsName, numberOfMetrics)

headerTable = ttFont.get(self.headerTag)
if headerTable is not None:
lastAdvance = metrics[-1][0]
lastIndex = len(metrics)
while metrics[lastIndex-2][0] == lastAdvance:
lastIndex -= 1
if lastIndex <= 1:
# all advances are equal
lastIndex = 1
break
additionalMetrics = metrics[lastIndex:]
additionalMetrics = [otRound(sb) for _, sb in additionalMetrics]
metrics = metrics[:lastIndex]
numberOfMetrics = len(metrics)
setattr(headerTable, self.numberOfMetricsName, numberOfMetrics)
else:
# no hhea/vhea, can't store numberOfMetrics; assume == numGlyphs
numberOfMetrics = ttFont["maxp"].numGlyphs
additionalMetrics = []

allMetrics = []
for advance, sb in metrics:
Expand Down
39 changes: 39 additions & 0 deletions Tests/ttLib/tables/_h_m_t_x_test.py
Expand Up @@ -107,6 +107,27 @@ def test_decompile_possibly_negative_advance(self):
len([r for r in captor.records
if "has a huge advance" in r.msg]) == 1)

def test_decompile_no_header_table(self):
font = TTFont()
maxp = font['maxp'] = newTable('maxp')
maxp.numGlyphs = 3
font.glyphOrder = ["A", "B", "C"]

self.assertNotIn(self.tableClass.headerTag, font)

data = deHexStr("0190 001E 0190 0028 0190 0032")
mtxTable = newTable(self.tag)
mtxTable.decompile(data, font)

self.assertEqual(
mtxTable.metrics,
{
"A": (400, 30),
"B": (400, 40),
"C": (400, 50),
}
)

def test_compile(self):
# we set the wrong 'numberOfMetrics' to check it gets adjusted
font = self.makeFont(numGlyphs=3, numberOfMetrics=4)
Expand Down Expand Up @@ -173,6 +194,24 @@ def test_compile_round_float_values(self):

self.assertEqual(data, deHexStr("0001 0001 0000 0001 0000"))

def test_compile_no_header_table(self):
font = TTFont()
maxp = font['maxp'] = newTable('maxp')
maxp.numGlyphs = 3
font.glyphOrder = [chr(i) for i in range(65, 68)]
mtxTable = font[self.tag] = newTable(self.tag)
mtxTable.metrics = {
"A": (400, 30),
"B": (400, 40),
"C": (400, 50),
}

self.assertNotIn(self.tableClass.headerTag, font)

data = mtxTable.compile(font)

self.assertEqual(data, deHexStr("0190 001E 0190 0028 0190 0032"))

def test_toXML(self):
font = self.makeFont(numGlyphs=2, numberOfMetrics=2)
mtxTable = font[self.tag] = newTable(self.tag)
Expand Down

0 comments on commit 8350332

Please sign in to comment.