Add glyf flags bit6 to ttx output (#1316)

* Implement glyf outline flags bit 6 when decompiling/compiling

* Add test data for outline flag bit 6

* Rename flags, use bitwise OR for setting flag bit

* Remove unneeded code
This commit is contained in:
Jens Kutilek 2018-09-14 15:27:32 +02:00 committed by Cosimo Lupo
parent 5c2ea41fa6
commit 7c8077a63d
7 changed files with 167 additions and 7 deletions

View File

@ -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

View File

@ -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())

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.29">
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="glyph00001"/>
<GlyphID id="2" name="glyph00002"/>
<GlyphID id="3" name="glyph00003"/>
</GlyphOrder>
<head>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.0"/>
<checkSumAdjustment value="0x6e4f1ccf"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00100000 00011011"/>
<unitsPerEm value="2048"/>
<created value="Thu Sep 13 14:22:20 2018"/>
<modified value="Fri Sep 14 09:25:13 2018"/>
<xMin value="12"/>
<yMin value="0"/>
<xMax value="1172"/>
<yMax value="1430"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="9"/>
<fontDirectionHint value="2"/>
<indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
<maxp>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="0x10000"/>
<numGlyphs value="4"/>
<maxPoints value="11"/>
<maxContours value="2"/>
<maxCompositePoints value="0"/>
<maxCompositeContours value="0"/>
<maxZones value="1"/>
<maxTwilightPoints value="0"/>
<maxStorage value="0"/>
<maxFunctionDefs value="10"/>
<maxInstructionDefs value="0"/>
<maxStackElements value="512"/>
<maxSizeOfInstructions value="353"/>
<maxComponentElements value="0"/>
<maxComponentDepth value="0"/>
</maxp>
<loca>
<!-- The 'loca' table will be calculated by the compiler -->
</loca>
<glyf>
<!-- The xMin, yMin, xMax and yMax values
will be recalculated by the compiler. -->
<TTGlyph name=".notdef"/><!-- contains no outline data -->
<TTGlyph name="glyph00001"/><!-- contains no outline data -->
<TTGlyph name="glyph00002"/><!-- contains no outline data -->
<TTGlyph name="glyph00003" xMin="12" yMin="0" xMax="1172" yMax="1430">
<contour>
<pt x="501" y="1430" on="1" overlap="1"/>
<pt x="683" y="1430" on="1"/>
<pt x="1172" y="0" on="1"/>
<pt x="983" y="0" on="1"/>
<pt x="591" y="1193" on="1"/>
<pt x="199" y="0" on="1"/>
<pt x="12" y="0" on="1"/>
</contour>
<contour>
<pt x="249" y="514" on="1"/>
<pt x="935" y="514" on="1"/>
<pt x="935" y="352" on="1"/>
<pt x="249" y="352" on="1"/>
</contour>
<instructions/>
</TTGlyph>
</glyf>
</ttFont>