Merge branch 'master' into fealib-duplicate-sub-warning
This commit is contained in:
commit
bf4fedaa74
@ -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"]
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
112
Lib/fontTools/pens/roundingPen.py
Normal file
112
Lib/fontTools/pens/roundingPen.py
Normal file
@ -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,
|
||||
)
|
@ -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', <Transform [2 0 0 2 -30 15]>), {'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))
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
18
NEWS.rst
18
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)
|
||||
---------------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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('<?xml version="1.0" encoding="UTF-8"?>\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:
|
||||
|
@ -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}
|
||||
|
Loading…
x
Reference in New Issue
Block a user