diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py index c1118c911..4ddf3d696 100644 --- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py +++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py @@ -260,8 +260,11 @@ flagYShort = 0x04 flagRepeat = 0x08 flagXsame = 0x10 flagYsame = 0x20 -flagReserved1 = 0x40 -flagReserved2 = 0x80 +flagOverlapSimple = 0x40 +flagReserved = 0x80 + +# These flags are kept for XML output after decompiling the coordinates +keepFlags = flagOnCurve + flagOverlapSimple _flagSignBytes = { 0: 2, @@ -408,10 +411,15 @@ class Glyph(object): writer.begintag("contour") writer.newline() for j in range(last, self.endPtsOfContours[i] + 1): - writer.simpletag("pt", [ + attrs = [ ("x", self.coordinates[j][0]), ("y", self.coordinates[j][1]), - ("on", self.flags[j] & flagOnCurve)]) + ("on", self.flags[j] & flagOnCurve), + ] + if self.flags[j] & flagOverlapSimple: + # Apple's rasterizer uses flagOverlapSimple in the first contour/first pt to flag glyphs that contain overlapping contours + attrs.append(("overlap", 1)) + writer.simpletag("pt", attrs) writer.newline() last = self.endPtsOfContours[i] + 1 writer.endtag("contour") @@ -441,7 +449,10 @@ class Glyph(object): if name != "pt": continue # ignore anything but "pt" coordinates.append((safeEval(attrs["x"]), safeEval(attrs["y"]))) - flags.append(not not safeEval(attrs["on"])) + flag = not not safeEval(attrs["on"]) + if "overlap" in attrs and bool(safeEval(attrs["overlap"])): + flag |= flagOverlapSimple + flags.append(flag) flags = array.array("B", flags) if not hasattr(self, "coordinates"): self.coordinates = coordinates @@ -560,8 +571,8 @@ class Glyph(object): assert xIndex == len(xCoordinates) assert yIndex == len(yCoordinates) coordinates.relativeToAbsolute() - # discard all flags but for "flagOnCurve" - self.flags = array.array("B", (f & flagOnCurve for f in flags)) + # discard all flags except "keepFlags" + self.flags = array.array("B", (f & keepFlags for f in flags)) def decompileCoordinatesRaw(self, nCoordinates, data): # unpack flags and prepare unpacking of coordinates diff --git a/Tests/ttLib/tables/_g_l_y_f_test.py b/Tests/ttLib/tables/_g_l_y_f_test.py index 205af8431..d07869241 100644 --- a/Tests/ttLib/tables/_g_l_y_f_test.py +++ b/Tests/ttLib/tables/_g_l_y_f_test.py @@ -1,10 +1,14 @@ from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.misc.fixedTools import otRound +from fontTools.ttLib import TTFont, newTable from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates import sys import array import pytest +import re +import os +import unittest class GlyphCoordinatesTest(object): @@ -158,3 +162,60 @@ class GlyphCoordinatesTest(object): g.append((0x8000, 0)) assert g.array.typecode == "d" assert g.array == array.array("d", [1.0, 1.0, 32768.0, 0.0]) + + +CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) +DATA_DIR = os.path.join(CURR_DIR, 'data') + +GLYF_TTX = os.path.join(DATA_DIR, "_g_l_y_f_outline_flag_bit6.ttx") +GLYF_BIN = os.path.join(DATA_DIR, "_g_l_y_f_outline_flag_bit6.glyf.bin") +HEAD_BIN = os.path.join(DATA_DIR, "_g_l_y_f_outline_flag_bit6.head.bin") +LOCA_BIN = os.path.join(DATA_DIR, "_g_l_y_f_outline_flag_bit6.loca.bin") +MAXP_BIN = os.path.join(DATA_DIR, "_g_l_y_f_outline_flag_bit6.maxp.bin") + + +def strip_ttLibVersion(string): + return re.sub(' ttLibVersion=".*"', '', string) + + +class glyfTableTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + with open(GLYF_BIN, 'rb') as f: + cls.glyfData = f.read() + with open(HEAD_BIN, 'rb') as f: + cls.headData = f.read() + with open(LOCA_BIN, 'rb') as f: + cls.locaData = f.read() + with open(MAXP_BIN, 'rb') as f: + cls.maxpData = f.read() + with open(GLYF_TTX, 'r') as f: + cls.glyfXML = strip_ttLibVersion(f.read()).splitlines() + + def test_toXML(self): + font = TTFont(sfntVersion="\x00\x01\x00\x00") + glyfTable = font['glyf'] = newTable('glyf') + font['head'] = newTable('head') + font['loca'] = newTable('loca') + font['maxp'] = newTable('maxp') + font['maxp'].decompile(self.maxpData, font) + font['head'].decompile(self.headData, font) + font['loca'].decompile(self.locaData, font) + glyfTable.decompile(self.glyfData, font) + out = UnicodeIO() + font.saveXML(out) + glyfXML = strip_ttLibVersion(out.getvalue()).splitlines() + self.assertEqual(glyfXML, self.glyfXML) + + def test_fromXML(self): + font = TTFont(sfntVersion="\x00\x01\x00\x00") + font.importXML(GLYF_TTX) + glyfTable = font['glyf'] + glyfData = glyfTable.compile(font) + self.assertEqual(glyfData, self.glyfData) + + +if __name__ == "__main__": + import sys + sys.exit(unittest.main()) diff --git a/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.glyf.bin b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.glyf.bin new file mode 100644 index 000000000..4e18ddbd0 Binary files /dev/null and b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.glyf.bin differ diff --git a/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.head.bin b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.head.bin new file mode 100644 index 000000000..3114f38b5 Binary files /dev/null and b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.head.bin differ diff --git a/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.loca.bin b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.loca.bin new file mode 100644 index 000000000..d0a95fd59 Binary files /dev/null and b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.loca.bin differ diff --git a/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.maxp.bin b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.maxp.bin new file mode 100644 index 000000000..7fbd12ebf Binary files /dev/null and b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.maxp.bin differ diff --git a/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.ttx b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.ttx new file mode 100644 index 000000000..d0194d623 --- /dev/null +++ b/Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.ttx @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +