Merge pull request #1829 from anthrotype/empty-glyf

[glyf] compile empty table as 1 null byte to make OTS and Windows happy
This commit is contained in:
Cosimo Lupo 2020-02-12 14:52:23 +00:00 committed by GitHub
commit e35228603d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 1 deletions

View File

@ -122,6 +122,12 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
ttFont['loca'].set(locations)
if 'maxp' in ttFont:
ttFont['maxp'].numGlyphs = len(self.glyphs)
if not data:
# As a special case when all glyph in the font are empty, add a zero byte
# to the table, so that OTS doesnt reject it, and to make the table work
# on Windows as well.
# See https://github.com/khaledhosny/ots/issues/52
data = b"\0"
return data
def toXML(self, writer, ttFont, splitGlyphs=False):

View File

@ -12,6 +12,8 @@ import shutil
import sys
import tempfile
import unittest
import pathlib
import pytest
class SubsetTest(unittest.TestCase):
@ -835,5 +837,40 @@ def test_subset_single_pos_format():
]
@pytest.fixture
def ttf_path(tmp_path):
# $(dirname $0)/../ttLib/data
ttLib_data = pathlib.Path(__file__).parent.parent / "ttLib" / "data"
font = TTFont()
font.importXML(ttLib_data / "TestTTF-Regular.ttx")
font_path = tmp_path / "TestTTF-Regular.ttf"
font.save(font_path)
return font_path
def test_subset_empty_glyf(tmp_path, ttf_path):
subset_path = tmp_path / (ttf_path.name + ".subset")
# only keep empty .notdef and space glyph, resulting in an empty glyf table
subset.main(
[
str(ttf_path),
"--no-notdef-outline",
"--glyph-names",
f"--output-file={subset_path}",
"--glyphs=.notdef space",
]
)
subset_font = TTFont(subset_path)
assert subset_font.getGlyphOrder() == [".notdef", "space"]
assert subset_font.reader['glyf'] == b"\x00"
glyf = subset_font["glyf"]
assert all(glyf[g].numberOfContours == 0 for g in subset_font.getGlyphOrder())
loca = subset_font["loca"]
assert all(loc == 0 for loc in loca)
if __name__ == "__main__":
sys.exit(unittest.main())

View File

@ -6,6 +6,7 @@ from fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
from fontTools.pens.pointPen import PointToSegmentPen
from fontTools.ttLib import TTFont, newTable, TTLibError
from fontTools.ttLib.tables._g_l_y_f import (
Glyph,
GlyphCoordinates,
GlyphComponent,
ARGS_ARE_XY_VALUES,
@ -190,7 +191,7 @@ def strip_ttLibVersion(string):
return re.sub(' ttLibVersion=".*"', '', string)
class glyfTableTest(unittest.TestCase):
class GlyfTableTest(unittest.TestCase):
def __init__(self, methodName):
unittest.TestCase.__init__(self, methodName)
@ -338,6 +339,28 @@ class glyfTableTest(unittest.TestCase):
glyfTable["glyph00003"].drawPoints(PointToSegmentPen(pen2), glyfTable)
self.assertEqual(pen1.value, pen2.value)
def test_compile_empty_table(self):
font = TTFont(sfntVersion="\x00\x01\x00\x00")
font.importXML(GLYF_TTX)
glyfTable = font['glyf']
# set all glyphs to zero contours
glyfTable.glyphs = {glyphName: Glyph() for glyphName in font.getGlyphOrder()}
glyfData = glyfTable.compile(font)
self.assertEqual(glyfData, b"\x00")
self.assertEqual(list(font["loca"]), [0] * (font["maxp"].numGlyphs+1))
def test_decompile_empty_table(self):
font = TTFont()
glyphNames = [".notdef", "space"]
font.setGlyphOrder(glyphNames)
font["loca"] = newTable("loca")
font["loca"].locations = [0] * (len(glyphNames) + 1)
font["glyf"] = newTable("glyf")
font["glyf"].decompile(b"\x00", font)
self.assertEqual(len(font["glyf"]), 2)
self.assertEqual(font["glyf"][".notdef"].numberOfContours, 0)
self.assertEqual(font["glyf"]["space"].numberOfContours, 0)
class GlyphComponentTest: