diff --git a/Lib/fontTools/__init__.py b/Lib/fontTools/__init__.py index 92f1e2cb9..79759acf1 100644 --- a/Lib/fontTools/__init__.py +++ b/Lib/fontTools/__init__.py @@ -4,6 +4,6 @@ from fontTools.misc.loggingTools import configLogger log = logging.getLogger(__name__) -version = __version__ = "4.1.1.dev0" +version = __version__ = "4.2.1.dev0" __all__ = ["version", "log", "configLogger"] diff --git a/Lib/fontTools/pens/filterPen.py b/Lib/fontTools/pens/filterPen.py index 0ebb9c23b..7539efb5c 100644 --- a/Lib/fontTools/pens/filterPen.py +++ b/Lib/fontTools/pens/filterPen.py @@ -1,12 +1,13 @@ from fontTools.misc.py23 import * from fontTools.pens.basePen import AbstractPen +from fontTools.pens.pointPen import AbstractPointPen from fontTools.pens.recordingPen import RecordingPen class _PassThruComponentsMixin(object): - def addComponent(self, glyphName, transformation): - self._outPen.addComponent(glyphName, transformation) + def addComponent(self, glyphName, transformation, **kwargs): + self._outPen.addComponent(glyphName, transformation, **kwargs) class FilterPen(_PassThruComponentsMixin, AbstractPen): @@ -118,3 +119,41 @@ class ContourFilterPen(_PassThruComponentsMixin, RecordingPen): Otherwise, the return value is drawn with the output pen. """ return # or return contour + + +class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen): + """ Baseclass for point pens that apply some transformation to the + coordinates they receive and pass them to another point pen. + + You can override any of its methods. The default implementation does + nothing, but passes the commands unmodified to the other pen. + + >>> from fontTools.pens.recordingPen import RecordingPointPen + >>> rec = RecordingPointPen() + >>> pen = FilterPointPen(rec) + >>> v = iter(rec.value) + >>> pen.beginPath(identifier="abc") + >>> next(v) + ('beginPath', (), {'identifier': 'abc'}) + >>> pen.addPoint((1, 2), "line", False) + >>> next(v) + ('addPoint', ((1, 2), 'line', False, None), {}) + >>> pen.addComponent("a", (2, 0, 0, 2, 10, -10), identifier="0001") + >>> next(v) + ('addComponent', ('a', (2, 0, 0, 2, 10, -10)), {'identifier': '0001'}) + >>> pen.endPath() + >>> next(v) + ('endPath', (), {}) + """ + + def __init__(self, outPointPen): + self._outPen = outPointPen + + def beginPath(self, **kwargs): + self._outPen.beginPath(**kwargs) + + def endPath(self): + self._outPen.endPath() + + def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): + self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs) diff --git a/Lib/fontTools/pens/recordingPen.py b/Lib/fontTools/pens/recordingPen.py index dbbcc916c..b25011d6d 100644 --- a/Lib/fontTools/pens/recordingPen.py +++ b/Lib/fontTools/pens/recordingPen.py @@ -1,9 +1,15 @@ """Pen recording operations that can be accessed or replayed.""" from fontTools.misc.py23 import * from fontTools.pens.basePen import AbstractPen, DecomposingPen +from fontTools.pens.pointPen import AbstractPointPen -__all__ = ["replayRecording", "RecordingPen", "DecomposingRecordingPen"] +__all__ = [ + "replayRecording", + "RecordingPen", + "DecomposingRecordingPen", + "RecordingPointPen", +] def replayRecording(recording, pen): @@ -89,6 +95,51 @@ class DecomposingRecordingPen(DecomposingPen, RecordingPen): skipMissingComponents = False +class RecordingPointPen(AbstractPointPen): + """PointPen recording operations that can be accessed or replayed. + + The recording can be accessed as pen.value; or replayed using + pointPen.replay(otherPointPen). + + Usage example: + ============== + from defcon import Font + from fontTools.pens.recordingPen import RecordingPointPen + + glyph_name = 'a' + font_path = 'MyFont.ufo' + + font = Font(font_path) + glyph = font[glyph_name] + + pen = RecordingPointPen() + glyph.drawPoints(pen) + print(pen.value) + + new_glyph = font.newGlyph('b') + pen.replay(new_glyph.getPointPen()) + """ + + def __init__(self): + self.value = [] + + def beginPath(self, **kwargs): + self.value.append(("beginPath", (), kwargs)) + + def endPath(self): + self.value.append(("endPath", (), {})) + + def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): + self.value.append(("addPoint", (pt, segmentType, smooth, name), kwargs)) + + def addComponent(self, baseGlyphName, transformation, **kwargs): + self.value.append(("addComponent", (baseGlyphName, transformation), kwargs)) + + def replay(self, pointPen): + for operator, args, kwargs in self.value: + getattr(pointPen, operator)(*args, **kwargs) + + if __name__ == "__main__": from fontTools.pens.basePen import _TestPen pen = RecordingPen() diff --git a/Lib/fontTools/pens/roundingPen.py b/Lib/fontTools/pens/roundingPen.py new file mode 100644 index 000000000..c032cad1f --- /dev/null +++ b/Lib/fontTools/pens/roundingPen.py @@ -0,0 +1,112 @@ +from fontTools.misc.fixedTools import otRound +from fontTools.misc.transform import Transform +from fontTools.pens.filterPen import FilterPen, FilterPointPen + + +__all__ = ["RoundingPen", "RoundingPointPen"] + + +class RoundingPen(FilterPen): + """ + Filter pen that rounds point coordinates and component XY offsets to integer. + + >>> from fontTools.pens.recordingPen import RecordingPen + >>> recpen = RecordingPen() + >>> roundpen = RoundingPen(recpen) + >>> roundpen.moveTo((0.4, 0.6)) + >>> roundpen.lineTo((1.6, 2.5)) + >>> roundpen.qCurveTo((2.4, 4.6), (3.3, 5.7), (4.9, 6.1)) + >>> roundpen.curveTo((6.4, 8.6), (7.3, 9.7), (8.9, 10.1)) + >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5)) + >>> recpen.value == [ + ... ('moveTo', ((0, 1),)), + ... ('lineTo', ((2, 3),)), + ... ('qCurveTo', ((2, 5), (3, 6), (5, 6))), + ... ('curveTo', ((6, 9), (7, 10), (9, 10))), + ... ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10))), + ... ] + True + """ + + def __init__(self, outPen, roundFunc=otRound): + super().__init__(outPen) + self.roundFunc = roundFunc + + def moveTo(self, pt): + self._outPen.moveTo((self.roundFunc(pt[0]), self.roundFunc(pt[1]))) + + def lineTo(self, pt): + self._outPen.lineTo((self.roundFunc(pt[0]), self.roundFunc(pt[1]))) + + def curveTo(self, *points): + self._outPen.curveTo( + *((self.roundFunc(x), self.roundFunc(y)) for x, y in points) + ) + + def qCurveTo(self, *points): + self._outPen.qCurveTo( + *((self.roundFunc(x), self.roundFunc(y)) for x, y in points) + ) + + def addComponent(self, glyphName, transformation): + self._outPen.addComponent( + glyphName, + Transform( + *transformation[:4], + self.roundFunc(transformation[4]), + self.roundFunc(transformation[5]), + ), + ) + + +class RoundingPointPen(FilterPointPen): + """ + Filter point pen that rounds point coordinates and component XY offsets to integer. + + >>> from fontTools.pens.recordingPen import RecordingPointPen + >>> recpen = RecordingPointPen() + >>> roundpen = RoundingPointPen(recpen) + >>> roundpen.beginPath() + >>> roundpen.addPoint((0.4, 0.6), 'line') + >>> roundpen.addPoint((1.6, 2.5), 'line') + >>> roundpen.addPoint((2.4, 4.6)) + >>> roundpen.addPoint((3.3, 5.7)) + >>> roundpen.addPoint((4.9, 6.1), 'qcurve') + >>> roundpen.endPath() + >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5)) + >>> recpen.value == [ + ... ('beginPath', (), {}), + ... ('addPoint', ((0, 1), 'line', False, None), {}), + ... ('addPoint', ((2, 3), 'line', False, None), {}), + ... ('addPoint', ((2, 5), None, False, None), {}), + ... ('addPoint', ((3, 6), None, False, None), {}), + ... ('addPoint', ((5, 6), 'qcurve', False, None), {}), + ... ('endPath', (), {}), + ... ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10)), {}), + ... ] + True + """ + + def __init__(self, outPen, roundFunc=otRound): + super().__init__(outPen) + self.roundFunc = roundFunc + + def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): + self._outPen.addPoint( + (self.roundFunc(pt[0]), self.roundFunc(pt[1])), + segmentType=segmentType, + smooth=smooth, + name=name, + **kwargs, + ) + + def addComponent(self, baseGlyphName, transformation, **kwargs): + self._outPen.addComponent( + baseGlyphName, + Transform( + *transformation[:4], + self.roundFunc(transformation[4]), + self.roundFunc(transformation[5]), + ), + **kwargs, + ) diff --git a/Lib/fontTools/pens/transformPen.py b/Lib/fontTools/pens/transformPen.py index 8d33a0865..6619ba739 100644 --- a/Lib/fontTools/pens/transformPen.py +++ b/Lib/fontTools/pens/transformPen.py @@ -1,5 +1,5 @@ from fontTools.misc.py23 import * -from fontTools.pens.filterPen import FilterPen +from fontTools.pens.filterPen import FilterPen, FilterPointPen __all__ = ["TransformPen"] @@ -55,6 +55,51 @@ class TransformPen(FilterPen): self._outPen.addComponent(glyphName, transformation) +class TransformPointPen(FilterPointPen): + """PointPen that transforms all coordinates using a Affine transformation, + and passes them to another PointPen. + + >>> from fontTools.pens.recordingPen import RecordingPointPen + >>> rec = RecordingPointPen() + >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5)) + >>> v = iter(rec.value) + >>> pen.beginPath(identifier="contour-0") + >>> next(v) + ('beginPath', (), {'identifier': 'contour-0'}) + >>> pen.addPoint((100, 100), "line") + >>> next(v) + ('addPoint', ((190, 205), 'line', False, None), {}) + >>> pen.endPath() + >>> next(v) + ('endPath', (), {}) + >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0") + >>> next(v) + ('addComponent', ('a', ), {'identifier': 'component-0'}) + """ + + def __init__(self, outPointPen, transformation): + """The 'outPointPen' argument is another point pen object. + It will receive the transformed coordinates. + The 'transformation' argument can either be a six-tuple, or a + fontTools.misc.transform.Transform object. + """ + super().__init__(outPointPen) + if not hasattr(transformation, "transformPoint"): + from fontTools.misc.transform import Transform + transformation = Transform(*transformation) + self._transformation = transformation + self._transformPoint = transformation.transformPoint + + def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): + self._outPen.addPoint( + self._transformPoint(pt), segmentType, smooth, name, **kwargs + ) + + def addComponent(self, baseGlyphName, transformation, **kwargs): + transformation = self._transformation.transform(transformation) + self._outPen.addComponent(baseGlyphName, transformation, **kwargs) + + if __name__ == "__main__": from fontTools.pens.basePen import _TestPen pen = TransformPen(_TestPen(None), (2, 0, 0.5, 2, -10, 0)) diff --git a/Lib/fontTools/pens/ttGlyphPen.py b/Lib/fontTools/pens/ttGlyphPen.py index 3996e3cd8..f7b1483b2 100644 --- a/Lib/fontTools/pens/ttGlyphPen.py +++ b/Lib/fontTools/pens/ttGlyphPen.py @@ -1,6 +1,6 @@ from fontTools.misc.py23 import * from array import array -from fontTools.misc.fixedTools import MAX_F2DOT14 +from fontTools.misc.fixedTools import MAX_F2DOT14, otRound from fontTools.pens.basePen import LoggingPen from fontTools.pens.transformPen import TransformPen from fontTools.ttLib.tables import ttProgram @@ -118,7 +118,7 @@ class TTGlyphPen(LoggingPen): component = GlyphComponent() component.glyphName = glyphName - component.x, component.y = transformation[4:] + component.x, component.y = (otRound(v) for v in transformation[4:]) transformation = transformation[:4] if transformation != (1, 0, 0, 1): if (self.handleOverflowingTransforms and @@ -138,6 +138,7 @@ class TTGlyphPen(LoggingPen): glyph = Glyph() glyph.coordinates = GlyphCoordinates(self.points) + glyph.coordinates.toInt() glyph.endPtsOfContours = self.endPts glyph.flags = array("B", self.types) self.init() diff --git a/Lib/fontTools/ufoLib/__init__.py b/Lib/fontTools/ufoLib/__init__.py index 8e22242e7..fb09bf6e5 100755 --- a/Lib/fontTools/ufoLib/__init__.py +++ b/Lib/fontTools/ufoLib/__init__.py @@ -339,7 +339,8 @@ class UFOReader(_UFOBaseIO): # convert kerning and groups kerning, groups, conversionMaps = convertUFO1OrUFO2KerningToUFO3Kerning( self._upConvertedKerningData["originalKerning"], - deepcopy(self._upConvertedKerningData["originalGroups"]) + deepcopy(self._upConvertedKerningData["originalGroups"]), + self.getGlyphSet() ) # store self._upConvertedKerningData["kerning"] = kerning @@ -637,7 +638,7 @@ class UFOReader(_UFOBaseIO): ``validateRead`` will validate the read data, by default it is set to the class's validate value, can be overridden. - ``validateWrte`` will validate the written data, by default it is set to the + ``validateWrite`` will validate the written data, by default it is set to the class's validate value, can be overridden. """ from fontTools.ufoLib.glifLib import GlyphSet diff --git a/Lib/fontTools/ufoLib/converters.py b/Lib/fontTools/ufoLib/converters.py index 0e2dae1a0..3b8112c35 100644 --- a/Lib/fontTools/ufoLib/converters.py +++ b/Lib/fontTools/ufoLib/converters.py @@ -6,16 +6,16 @@ Conversion functions. # adapted from the UFO spec -def convertUFO1OrUFO2KerningToUFO3Kerning(kerning, groups): +def convertUFO1OrUFO2KerningToUFO3Kerning(kerning, groups, glyphSet=()): # gather known kerning groups based on the prefixes firstReferencedGroups, secondReferencedGroups = findKnownKerningGroups(groups) # Make lists of groups referenced in kerning pairs. for first, seconds in list(kerning.items()): - if first in groups: + if first in groups and first not in glyphSet: if not first.startswith("public.kern1."): firstReferencedGroups.add(first) for second in list(seconds.keys()): - if second in groups: + if second in groups and second not in glyphSet: if not second.startswith("public.kern2."): secondReferencedGroups.add(second) # Create new names for these groups. @@ -154,7 +154,7 @@ def test(): ... "DGroup" : ["D"], ... } >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( - ... testKerning, testGroups) + ... testKerning, testGroups, []) >>> expected = { ... "A" : { ... "A": 1, @@ -220,7 +220,7 @@ def test(): ... "@MMK_R_XGroup" : ["X"], ... } >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( - ... testKerning, testGroups) + ... testKerning, testGroups, []) >>> expected = { ... "A" : { ... "A": 1, @@ -293,7 +293,7 @@ def test(): ... "DGroup" : ["D"], ... } >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( - ... testKerning, testGroups) + ... testKerning, testGroups, []) >>> expected = { ... "A" : { ... "A": 1, diff --git a/Lib/fontTools/ufoLib/validators.py b/Lib/fontTools/ufoLib/validators.py index 3f35d35a2..49cb0e49d 100644 --- a/Lib/fontTools/ufoLib/validators.py +++ b/Lib/fontTools/ufoLib/validators.py @@ -883,7 +883,7 @@ def groupsValidator(value): return False, "A group has an empty name." if groupName.startswith("public."): if not groupName.startswith("public.kern1.") and not groupName.startswith("public.kern2."): - # unknown pubic.* name. silently skip. + # unknown public.* name. silently skip. continue else: if len("public.kernN.") == len(groupName): diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py index 80bd09b4b..66dfa3572 100644 --- a/Lib/fontTools/varLib/__init__.py +++ b/Lib/fontTools/varLib/__init__.py @@ -795,7 +795,7 @@ def set_default_weight_width_slant(font, location): if "wght" in location: weight_class = otRound(max(1, min(location["wght"], 1000))) if font["OS/2"].usWeightClass != weight_class: - log.info("Setting OS/2.usWidthClass = %s", weight_class) + log.info("Setting OS/2.usWeightClass = %s", weight_class) font["OS/2"].usWeightClass = weight_class if "wdth" in location: diff --git a/NEWS.rst b/NEWS.rst index 56e3d58e3..37834877b 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,21 @@ +4.2.0 (released 2019-11-28) +--------------------------- + +- [pens] Added the following pens: + + * ``roundingPen.RoundingPen``: filter pen that rounds coordinates and components' + offsets to integer; + * ``roundingPen.RoundingPointPen``: like the above, but using PointPen protocol. + * ``filterPen.FilterPointPen``: base class for filter point pens; + * ``transformPen.TransformPointPen``: filter point pen to apply affine transform; + * ``recordingPen.RecordingPointPen``: records and replays point-pen commands. + +- [ttGlyphPen] Always round float coordinates and component offsets to integers + (#1763). +- [ufoLib] When converting kerning groups from UFO2 to UFO3, avoid confusing + groups with the same name as one of the glyphs (#1761, #1762, + unified-font-object/ufo-spec#98). + 4.1.0 (released 2019-11-18) --------------------------- diff --git a/Tests/pens/recordingPen_test.py b/Tests/pens/recordingPen_test.py index 971536d7a..6977b93b0 100644 --- a/Tests/pens/recordingPen_test.py +++ b/Tests/pens/recordingPen_test.py @@ -1,19 +1,29 @@ -from fontTools.misc.py23 import * -from fontTools.pens.recordingPen import RecordingPen, DecomposingRecordingPen +from fontTools.pens.recordingPen import ( + RecordingPen, + DecomposingRecordingPen, + RecordingPointPen, +) import pytest class _TestGlyph(object): - def draw(self, pen): pen.moveTo((0.0, 0.0)) pen.lineTo((0.0, 100.0)) pen.curveTo((50.0, 75.0), (60.0, 50.0), (50.0, 0.0)) pen.closePath() + def drawPoints(self, pen): + pen.beginPath(identifier="abc") + pen.addPoint((0.0, 0.0), "line", False, "start", identifier="0000") + pen.addPoint((0.0, 100.0), "line", False, None, identifier="0001") + pen.addPoint((50.0, 75.0), None, False, None, identifier="0002") + pen.addPoint((60.0, 50.0), None, False, None, identifier="0003") + pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004") + pen.endPath() + class RecordingPenTest(object): - def test_addComponent(self): pen = RecordingPen() pen.addComponent("a", (2, 0, 0, 3, -10, 5)) @@ -21,18 +31,42 @@ class RecordingPenTest(object): class DecomposingRecordingPenTest(object): - def test_addComponent_decomposed(self): pen = DecomposingRecordingPen({"a": _TestGlyph()}) pen.addComponent("a", (2, 0, 0, 3, -10, 5)) assert pen.value == [ - ('moveTo', ((-10.0, 5.0),)), - ('lineTo', ((-10.0, 305.0),)), - ('curveTo', ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0),)), - ('closePath', ())] + ("moveTo", ((-10.0, 5.0),)), + ("lineTo", ((-10.0, 305.0),)), + ("curveTo", ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0))), + ("closePath", ()), + ] def test_addComponent_missing_raises(self): pen = DecomposingRecordingPen(dict()) with pytest.raises(KeyError) as excinfo: pen.addComponent("a", (1, 0, 0, 1, 0, 0)) assert excinfo.value.args[0] == "a" + + +class RecordingPointPenTest: + def test_record_and_replay(self): + pen = RecordingPointPen() + glyph = _TestGlyph() + glyph.drawPoints(pen) + pen.addComponent("a", (2, 0, 0, 2, -10, 5)) + + assert pen.value == [ + ("beginPath", (), {"identifier": "abc"}), + ("addPoint", ((0.0, 0.0), "line", False, "start"), {"identifier": "0000"}), + ("addPoint", ((0.0, 100.0), "line", False, None), {"identifier": "0001"}), + ("addPoint", ((50.0, 75.0), None, False, None), {"identifier": "0002"}), + ("addPoint", ((60.0, 50.0), None, False, None), {"identifier": "0003"}), + ("addPoint", ((50.0, 0.0), "curve", True, "last"), {"identifier": "0004"}), + ("endPath", (), {}), + ("addComponent", ("a", (2, 0, 0, 2, -10, 5)), {}), + ] + + pen2 = RecordingPointPen() + pen.replay(pen2) + + assert pen2.value == pen.value diff --git a/Tests/pens/ttGlyphPen_test.py b/Tests/pens/ttGlyphPen_test.py index ec9458903..961738d47 100644 --- a/Tests/pens/ttGlyphPen_test.py +++ b/Tests/pens/ttGlyphPen_test.py @@ -239,6 +239,31 @@ class TTGlyphPenTest(TestCase): with self.assertRaises(struct.error): compositeGlyph.compile({'a': baseGlyph}) + def assertGlyphBoundsEqual(self, glyph, bounds): + self.assertEqual((glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax), bounds) + + def test_round_float_coordinates_and_component_offsets(self): + glyphSet = {} + pen = TTGlyphPen(glyphSet) + + pen.moveTo((0, 0)) + pen.lineTo((0, 1)) + pen.lineTo((367.6, 0)) + pen.closePath() + simpleGlyph = pen.glyph() + + simpleGlyph.recalcBounds(glyphSet) + self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1)) + + componentName = 'a' + glyphSet[componentName] = simpleGlyph + + pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0)) + compositeGlyph = pen.glyph() + + compositeGlyph.recalcBounds(glyphSet) + self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1)) + class _TestGlyph(object): def __init__(self, glyph): diff --git a/Tests/ufoLib/UFOConversion_test.py b/Tests/ufoLib/UFOConversion_test.py index c19bc0ce1..98a08121c 100644 --- a/Tests/ufoLib/UFOConversion_test.py +++ b/Tests/ufoLib/UFOConversion_test.py @@ -137,7 +137,9 @@ class KerningUpConversionTestCase(unittest.TestCase): ("A", "public.kern2.CGroup"): 3, ("A", "public.kern2.DGroup"): 4, ("A", "A"): 1, - ("A", "B"): 2 + ("A", "B"): 2, + ("X", "A"): 13, + ("X", "public.kern2.CGroup"): 14 } expectedGroups = { @@ -148,7 +150,8 @@ class KerningUpConversionTestCase(unittest.TestCase): "public.kern1.CGroup": ["C", "Ccedilla"], "public.kern2.CGroup": ["C", "Ccedilla"], "public.kern2.DGroup": ["D"], - "Not A Kerning Group" : ["A"] + "Not A Kerning Group" : ["A"], + "X": ["X", "X.sc"] } def setUp(self): @@ -163,6 +166,20 @@ class KerningUpConversionTestCase(unittest.TestCase): self.clearUFO() if not os.path.exists(self.ufoPath): os.mkdir(self.ufoPath) + + # glyphs + glyphsPath = os.path.join(self.ufoPath, "glyphs") + if not os.path.exists(glyphsPath): + os.mkdir(glyphsPath) + glyphFile = "X_.glif" + glyphsContents = dict(X=glyphFile) + path = os.path.join(glyphsPath, "contents.plist") + with open(path, "wb") as f: + plistlib.dump(glyphsContents, f) + path = os.path.join(glyphsPath, glyphFile) + with open(path, "w") as f: + f.write('\n') + # metainfo.plist metaInfo = dict(creator="test", formatVersion=formatVersion) path = os.path.join(self.ufoPath, "metainfo.plist") @@ -187,6 +204,10 @@ class KerningUpConversionTestCase(unittest.TestCase): "B" : 10, "CGroup" : 11, "DGroup" : 12 + }, + "X": { + "A" : 13, + "CGroup" : 14 } } path = os.path.join(self.ufoPath, "kerning.plist") @@ -197,7 +218,8 @@ class KerningUpConversionTestCase(unittest.TestCase): "BGroup" : ["B"], "CGroup" : ["C", "Ccedilla"], "DGroup" : ["D"], - "Not A Kerning Group" : ["A"] + "Not A Kerning Group" : ["A"], + "X" : ["X", "X.sc"] # a group with a name that is also a glyph name } path = os.path.join(self.ufoPath, "groups.plist") with open(path, "wb") as f: diff --git a/setup.cfg b/setup.cfg index 35faac4f2..da9d3f3e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.1.1.dev0 +current_version = 4.2.1.dev0 commit = True tag = False tag_name = {new_version} diff --git a/setup.py b/setup.py index 2b93a84f8..fb017ed06 100755 --- a/setup.py +++ b/setup.py @@ -345,7 +345,7 @@ def find_data_files(manpath="share/man"): setup( name="fonttools", - version="4.1.1.dev0", + version="4.2.1.dev0", description="Tools to manipulate font files", author="Just van Rossum", author_email="just@letterror.com",