Merge pull request #819 from jenskutilek/master
Indent XML output for TT assembly instructions
This commit is contained in:
commit
100304a445
@ -15,7 +15,6 @@ class table__f_p_g_m(DefaultTable.DefaultTable):
|
||||
|
||||
def toXML(self, writer, ttFont):
|
||||
self.program.toXML(writer, ttFont)
|
||||
writer.newline()
|
||||
|
||||
def fromXML(self, name, attrs, content, ttFont):
|
||||
program = ttProgram.Program()
|
||||
|
@ -354,11 +354,7 @@ class Glyph(object):
|
||||
if self.isComposite():
|
||||
for compo in self.components:
|
||||
compo.toXML(writer, ttFont)
|
||||
if hasattr(self, "program"):
|
||||
writer.begintag("instructions")
|
||||
self.program.toXML(writer, ttFont)
|
||||
writer.endtag("instructions")
|
||||
writer.newline()
|
||||
haveInstructions = hasattr(self, "program")
|
||||
else:
|
||||
last = 0
|
||||
for i in range(self.numberOfContours):
|
||||
@ -373,11 +369,16 @@ class Glyph(object):
|
||||
last = self.endPtsOfContours[i] + 1
|
||||
writer.endtag("contour")
|
||||
writer.newline()
|
||||
if self.numberOfContours:
|
||||
haveInstructions = self.numberOfContours > 0
|
||||
if haveInstructions:
|
||||
if self.program:
|
||||
writer.begintag("instructions")
|
||||
writer.newline()
|
||||
self.program.toXML(writer, ttFont)
|
||||
writer.endtag("instructions")
|
||||
writer.newline()
|
||||
else:
|
||||
writer.simpletag("instructions")
|
||||
writer.newline()
|
||||
|
||||
def fromXML(self, name, attrs, content, ttFont):
|
||||
if name == "contour":
|
||||
|
@ -194,6 +194,8 @@ _whiteRE = re.compile(r"\s*")
|
||||
|
||||
_pushCountPat = re.compile(r"[A-Z][A-Z0-9]*\s*\[.*?\]\s*/\* ([0-9]+).*?\*/")
|
||||
|
||||
_indentRE = re.compile("^FDEF|IF|ELSE\[ \]\t.+")
|
||||
_unindentRE = re.compile("^ELSE|ENDF|EIF\[ \]\t.+")
|
||||
|
||||
def _skipWhite(data, pos):
|
||||
m = _whiteRE.match(data, pos)
|
||||
@ -244,13 +246,20 @@ class Program(object):
|
||||
writer.newline()
|
||||
writer.dumphex(self.getBytecode())
|
||||
writer.endtag("bytecode")
|
||||
writer.newline()
|
||||
else:
|
||||
if not assembly:
|
||||
return
|
||||
writer.begintag("assembly")
|
||||
writer.newline()
|
||||
i = 0
|
||||
indent = 0
|
||||
nInstr = len(assembly)
|
||||
while i < nInstr:
|
||||
instr = assembly[i]
|
||||
if _unindentRE.match(instr):
|
||||
indent -= 1
|
||||
writer.write(writer.indentwhite * indent)
|
||||
writer.write(instr)
|
||||
writer.newline()
|
||||
m = _pushCountPat.match(instr)
|
||||
@ -261,19 +270,28 @@ class Program(object):
|
||||
j = 0
|
||||
for j in range(nValues):
|
||||
if j and not (j % 25):
|
||||
writer.write(writer.indentwhite * indent)
|
||||
writer.write(' '.join(line))
|
||||
writer.newline()
|
||||
line = []
|
||||
line.append(assembly[i+j])
|
||||
writer.write(writer.indentwhite * indent)
|
||||
writer.write(' '.join(line))
|
||||
writer.newline()
|
||||
i = i + j + 1
|
||||
if _indentRE.match(instr):
|
||||
indent += 1
|
||||
writer.endtag("assembly")
|
||||
writer.newline()
|
||||
else:
|
||||
bytecode = self.getBytecode()
|
||||
if not bytecode:
|
||||
return
|
||||
writer.begintag("bytecode")
|
||||
writer.newline()
|
||||
writer.dumphex(self.getBytecode())
|
||||
writer.dumphex(bytecode)
|
||||
writer.endtag("bytecode")
|
||||
writer.newline()
|
||||
|
||||
def fromXML(self, name, attrs, content, ttFont):
|
||||
if name == "assembly":
|
||||
@ -285,7 +303,7 @@ class Program(object):
|
||||
self.fromBytecode(readHex(content))
|
||||
|
||||
def _assemble(self):
|
||||
assembly = self.assembly
|
||||
assembly = getattr(self, 'assembly', [])
|
||||
if isinstance(assembly, type([])):
|
||||
assembly = ' '.join(assembly)
|
||||
bytecode = []
|
||||
@ -410,7 +428,7 @@ class Program(object):
|
||||
def _disassemble(self, preserve=False):
|
||||
assembly = []
|
||||
i = 0
|
||||
bytecode = self.bytecode
|
||||
bytecode = getattr(self, 'bytecode', [])
|
||||
numBytecode = len(bytecode)
|
||||
while i < numBytecode:
|
||||
op = bytecode[i]
|
||||
|
3
NEWS.rst
3
NEWS.rst
@ -1,3 +1,6 @@
|
||||
- Assembly code in the fpgm, prep, and glyf tables is now indented in
|
||||
XML output for improved readability. The ``instruction`` element is
|
||||
written as a simple tag if empty (#819).
|
||||
- [ttx] Fixed 'I/O operation on closed file' error when dumping
|
||||
multiple TTXs to standard output with the '-o -' option.
|
||||
- The unit test modules (``*_test.py``) have been moved outside of the
|
||||
|
@ -36,8 +36,7 @@
|
||||
<pt x="666" y="0" on="0"/>
|
||||
<pt x="334" y="0" on="0"/>
|
||||
</contour>
|
||||
<instructions><assembly>
|
||||
</assembly></instructions>
|
||||
<instructions/>
|
||||
</TTGlyph>
|
||||
|
||||
<TTGlyph name="glyph00003" xMin="100" yMin="0" xMax="900" yMax="800">
|
||||
@ -61,8 +60,7 @@
|
||||
<pt x="653" y="770" on="0"/>
|
||||
<pt x="347" y="770" on="0"/>
|
||||
</contour>
|
||||
<instructions><assembly>
|
||||
</assembly></instructions>
|
||||
<instructions/>
|
||||
</TTGlyph>
|
||||
|
||||
<TTGlyph name="glyph00004" xMin="238" yMin="181" xMax="761" yMax="606">
|
||||
@ -106,8 +104,7 @@
|
||||
<pt x="354" y="430" on="0"/>
|
||||
<pt x="320" y="430" on="0"/>
|
||||
</contour>
|
||||
<instructions><assembly>
|
||||
</assembly></instructions>
|
||||
<instructions/>
|
||||
</TTGlyph>
|
||||
|
||||
<TTGlyph name="smileface" xMin="100" yMin="0" xMax="900" yMax="800">
|
||||
@ -171,8 +168,7 @@
|
||||
<pt x="354" y="430" on="0"/>
|
||||
<pt x="320" y="430" on="0"/>
|
||||
</contour>
|
||||
<instructions><assembly>
|
||||
</assembly></instructions>
|
||||
<instructions/>
|
||||
</TTGlyph>
|
||||
|
||||
</glyf>
|
||||
|
1627
Tests/ttLib/tables/data/ttProgram.ttx
Normal file
1627
Tests/ttLib/tables/data/ttProgram.ttx
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,18 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.xmlWriter import XMLWriter
|
||||
from fontTools.ttLib.tables.ttProgram import Program
|
||||
from fontTools.misc.textTools import deHexStr
|
||||
import array
|
||||
import os
|
||||
import re
|
||||
import unittest
|
||||
|
||||
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
|
||||
DATA_DIR = os.path.join(CURR_DIR, 'data')
|
||||
|
||||
TTPROGRAM_TTX = os.path.join(DATA_DIR, "ttProgram.ttx")
|
||||
#TTPROGRAM_BIN = os.path.join(DATA_DIR, "ttProgram.bin")
|
||||
|
||||
BYTECODE = deHexStr(
|
||||
'403b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a'
|
||||
@ -58,7 +67,11 @@ BYTECODE = deHexStr(
|
||||
'20392f2d')
|
||||
|
||||
|
||||
class ProgramTest(object):
|
||||
class TestFont(object):
|
||||
disassembleInstructions = True
|
||||
|
||||
|
||||
class ProgramTest(unittest.TestCase):
|
||||
|
||||
def test__bool__(self):
|
||||
p = Program()
|
||||
@ -85,3 +98,22 @@ class ProgramTest(object):
|
||||
asm = p.getAssembly(preserve=True)
|
||||
p.fromAssembly(asm)
|
||||
assert BYTECODE == p.getBytecode()
|
||||
|
||||
def test_xml_indentation(self):
|
||||
with open(TTPROGRAM_TTX, 'r', encoding='utf-8') as f:
|
||||
ttProgramXML = f.read()
|
||||
p = Program()
|
||||
p.fromBytecode(BYTECODE)
|
||||
ttfont = TestFont()
|
||||
buf = UnicodeIO()
|
||||
writer = XMLWriter(buf, newlinestr='\n')
|
||||
try:
|
||||
p.toXML(writer, ttfont)
|
||||
finally:
|
||||
output_string = buf.getvalue()
|
||||
assert output_string == ttProgramXML
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
||||
|
Loading…
x
Reference in New Issue
Block a user