From c60512de0ea17bf2a5f1d65c63280bb437ecb436 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Mon, 7 Oct 2019 16:46:42 +0100 Subject: [PATCH] _g_l_y_f: use floatToFixedToStr and strToFixedToFloat in GlyphComponent toXML/fromXML --- Lib/fontTools/ttLib/tables/_g_l_y_f.py | 31 +++--- Tests/ttLib/tables/_g_l_y_f_test.py | 129 ++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 14 deletions(-) diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py index d22322c75..050e8d5dc 100644 --- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py +++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py @@ -11,6 +11,8 @@ from fontTools.misc.bezierTools import calcQuadraticBounds from fontTools.misc.fixedTools import ( fixedToFloat as fi2fl, floatToFixed as fl2fi, + floatToFixedToStr as fl2str, + strToFixedToFloat as str2fl, otRound, ) from numbers import Number @@ -1365,15 +1367,18 @@ class GlyphComponent(object): transform = self.transform if transform[0][1] or transform[1][0]: attrs = attrs + [ - ("scalex", transform[0][0]), ("scale01", transform[0][1]), - ("scale10", transform[1][0]), ("scaley", transform[1][1]), - ] + ("scalex", fl2str(transform[0][0], 14)), + ("scale01", fl2str(transform[0][1], 14)), + ("scale10", fl2str(transform[1][0], 14)), + ("scaley", fl2str(transform[1][1], 14)), + ] elif transform[0][0] != transform[1][1]: attrs = attrs + [ - ("scalex", transform[0][0]), ("scaley", transform[1][1]), - ] + ("scalex", fl2str(transform[0][0], 14)), + ("scaley", fl2str(transform[1][1], 14)), + ] else: - attrs = attrs + [("scale", transform[0][0])] + attrs = attrs + [("scale", fl2str(transform[0][0], 14))] attrs = attrs + [("flags", hex(self.flags))] writer.simpletag("component", attrs) writer.newline() @@ -1387,17 +1392,17 @@ class GlyphComponent(object): self.x = safeEval(attrs["x"]) self.y = safeEval(attrs["y"]) if "scale01" in attrs: - scalex = safeEval(attrs["scalex"]) - scale01 = safeEval(attrs["scale01"]) - scale10 = safeEval(attrs["scale10"]) - scaley = safeEval(attrs["scaley"]) + scalex = str2fl(attrs["scalex"], 14) + scale01 = str2fl(attrs["scale01"], 14) + scale10 = str2fl(attrs["scale10"], 14) + scaley = str2fl(attrs["scaley"], 14) self.transform = [[scalex, scale01], [scale10, scaley]] elif "scalex" in attrs: - scalex = safeEval(attrs["scalex"]) - scaley = safeEval(attrs["scaley"]) + scalex = str2fl(attrs["scalex"], 14) + scaley = str2fl(attrs["scaley"], 14) self.transform = [[scalex, 0], [0, scaley]] elif "scale" in attrs: - scale = safeEval(attrs["scale"]) + scale = str2fl(attrs["scale"], 14) self.transform = [[scale, 0], [0, scale]] self.flags = safeEval(attrs["flags"]) diff --git a/Tests/ttLib/tables/_g_l_y_f_test.py b/Tests/ttLib/tables/_g_l_y_f_test.py index db014b4a3..583d7672d 100644 --- a/Tests/ttLib/tables/_g_l_y_f_test.py +++ b/Tests/ttLib/tables/_g_l_y_f_test.py @@ -1,11 +1,20 @@ from fontTools.misc.py23 import * from fontTools.misc.fixedTools import otRound +from fontTools.misc.testTools import getXML, parseXML from fontTools.pens.ttGlyphPen import TTGlyphPen from fontTools.ttLib import TTFont, newTable, TTLibError -from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates +from fontTools.ttLib.tables._g_l_y_f import ( + GlyphCoordinates, + GlyphComponent, + ARGS_ARE_XY_VALUES, + WE_HAVE_A_SCALE, + WE_HAVE_A_TWO_BY_TWO, + WE_HAVE_AN_X_AND_Y_SCALE, +) from fontTools.ttLib.tables import ttProgram import sys import array +import itertools import pytest import re import os @@ -276,6 +285,124 @@ class glyfTableTest(unittest.TestCase): composite.compact(glyfTable) +class GlyphComponentTest: + + def test_toXML_no_transform(self): + comp = GlyphComponent() + comp.glyphName = "a" + comp.flags = ARGS_ARE_XY_VALUES + comp.x, comp.y = 1, 2 + + assert getXML(comp.toXML) == [ + '' + ] + + def test_toXML_transform_scale(self): + comp = GlyphComponent() + comp.glyphName = "a" + comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_A_SCALE + comp.x, comp.y = 1, 2 + + comp.transform = [[0.2999878, 0], [0, 0.2999878]] + assert getXML(comp.toXML) == [ + '' + ] + + def test_toXML_transform_xy_scale(self): + comp = GlyphComponent() + comp.glyphName = "a" + comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_AN_X_AND_Y_SCALE + comp.x, comp.y = 1, 2 + + comp.transform = [[0.5999756, 0], [0, 0.2999878]] + assert getXML(comp.toXML) == [ + '' + ] + + def test_toXML_transform_2x2_scale(self): + comp = GlyphComponent() + comp.glyphName = "a" + comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_A_TWO_BY_TWO + comp.x, comp.y = 1, 2 + + comp.transform = [[0.5999756, -0.2000122], [0.2000122, 0.2999878]] + assert getXML(comp.toXML) == [ + '' + ] + + def test_fromXML_no_transform(self): + comp = GlyphComponent() + for name, attrs, content in parseXML( + [''] + ): + comp.fromXML(name, attrs, content, ttFont=None) + + assert comp.glyphName == "a" + assert comp.flags & ARGS_ARE_XY_VALUES != 0 + assert (comp.x, comp.y) == (1, 2) + assert not hasattr(comp, "transform") + + def test_fromXML_transform_scale(self): + comp = GlyphComponent() + for name, attrs, content in parseXML( + [''] + ): + comp.fromXML(name, attrs, content, ttFont=None) + + assert comp.glyphName == "a" + assert comp.flags & ARGS_ARE_XY_VALUES != 0 + assert comp.flags & WE_HAVE_A_SCALE != 0 + assert (comp.x, comp.y) == (1, 2) + assert hasattr(comp, "transform") + for value, expected in zip( + itertools.chain(*comp.transform), [0.2999878, 0, 0, 0.2999878] + ): + assert value == pytest.approx(expected) + + def test_fromXML_transform_xy_scale(self): + comp = GlyphComponent() + for name, attrs, content in parseXML( + [ + '' + ] + ): + comp.fromXML(name, attrs, content, ttFont=None) + + assert comp.glyphName == "a" + assert comp.flags & ARGS_ARE_XY_VALUES != 0 + assert comp.flags & WE_HAVE_AN_X_AND_Y_SCALE != 0 + assert (comp.x, comp.y) == (1, 2) + assert hasattr(comp, "transform") + for value, expected in zip( + itertools.chain(*comp.transform), [0.5999756, 0, 0, 0.2999878] + ): + assert value == pytest.approx(expected) + + def test_fromXML_transform_2x2_scale(self): + comp = GlyphComponent() + for name, attrs, content in parseXML( + [ + '' + ] + ): + comp.fromXML(name, attrs, content, ttFont=None) + + assert comp.glyphName == "a" + assert comp.flags & ARGS_ARE_XY_VALUES != 0 + assert comp.flags & WE_HAVE_A_TWO_BY_TWO != 0 + assert (comp.x, comp.y) == (1, 2) + assert hasattr(comp, "transform") + for value, expected in zip( + itertools.chain(*comp.transform), + [0.5999756, -0.2000122, 0.2000122, 0.2999878] + ): + assert value == pytest.approx(expected) + + if __name__ == "__main__": import sys sys.exit(unittest.main())