also check endPtsOfContours in dropImpliedOnCurvePoints
as per review https://github.com/fonttools/fonttools/pull/3147#discussion_r1214708207 Also, don't do same work multiple times when dropping points from flags/endPtsOfContours arrays since these are supposed to be the same for all interpolatable glyphs
This commit is contained in:
parent
0690703b86
commit
5b93100616
@ -28,6 +28,7 @@ from fontTools.misc import xmlWriter
|
||||
from fontTools.misc.filenames import userNameToFileName
|
||||
from fontTools.misc.loggingTools import deprecateFunction
|
||||
from enum import IntFlag
|
||||
from types import SimpleNamespace
|
||||
from typing import Set
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -1558,8 +1559,9 @@ def dropImpliedOnCurvePoints(*interpolatable_glyphs: Glyph) -> Set[int]:
|
||||
Reference:
|
||||
https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
|
||||
"""
|
||||
numContours = None
|
||||
flags = None
|
||||
staticAttributes = SimpleNamespace(
|
||||
numberOfContours=None, flags=None, endPtsOfContours=None
|
||||
)
|
||||
drop = None
|
||||
simple_glyphs = []
|
||||
for i, glyph in enumerate(interpolatable_glyphs):
|
||||
@ -1567,26 +1569,23 @@ def dropImpliedOnCurvePoints(*interpolatable_glyphs: Glyph) -> Set[int]:
|
||||
# ignore composite or empty glyphs
|
||||
continue
|
||||
|
||||
if numContours is None:
|
||||
numContours = glyph.numberOfContours
|
||||
elif glyph.numberOfContours != numContours:
|
||||
raise ValueError(
|
||||
f"Incompatible number of contours for glyph at master index {i}: "
|
||||
f"expected {numContours}, found {glyph.numberOfContours}"
|
||||
)
|
||||
|
||||
if flags is None:
|
||||
flags = glyph.flags
|
||||
elif glyph.flags != flags:
|
||||
raise ValueError(
|
||||
f"Incompatible flags for simple glyph at master index {i}: "
|
||||
f"expected {flags}, found {glyph.flags}"
|
||||
)
|
||||
for attr in staticAttributes.__dict__:
|
||||
expected = getattr(staticAttributes, attr)
|
||||
found = getattr(glyph, attr)
|
||||
if expected is None:
|
||||
setattr(staticAttributes, attr, found)
|
||||
elif expected != found:
|
||||
raise ValueError(
|
||||
f"Incompatible {attr} for glyph at master index {i}: "
|
||||
f"expected {expected}, found {found}"
|
||||
)
|
||||
|
||||
may_drop = set()
|
||||
start = 0
|
||||
coords = glyph.coordinates
|
||||
for last in glyph.endPtsOfContours:
|
||||
flags = staticAttributes.flags
|
||||
endPtsOfContours = staticAttributes.endPtsOfContours
|
||||
for last in endPtsOfContours:
|
||||
for i in range(start, last + 1):
|
||||
if not (flags[i] & flagOnCurve):
|
||||
continue
|
||||
@ -1613,27 +1612,32 @@ def dropImpliedOnCurvePoints(*interpolatable_glyphs: Glyph) -> Set[int]:
|
||||
|
||||
if drop:
|
||||
# Do the actual dropping
|
||||
flags = staticAttributes.flags
|
||||
assert flags is not None
|
||||
newFlags = array.array(
|
||||
"B", (flags[i] for i in range(len(flags)) if i not in drop)
|
||||
)
|
||||
|
||||
endPts = staticAttributes.endPtsOfContours
|
||||
assert endPts is not None
|
||||
newEndPts = []
|
||||
i = 0
|
||||
delta = 0
|
||||
for d in sorted(drop):
|
||||
while d > endPts[i]:
|
||||
newEndPts.append(endPts[i] - delta)
|
||||
i += 1
|
||||
delta += 1
|
||||
while i < len(endPts):
|
||||
newEndPts.append(endPts[i] - delta)
|
||||
i += 1
|
||||
|
||||
for glyph in simple_glyphs:
|
||||
coords = glyph.coordinates
|
||||
glyph.coordinates = GlyphCoordinates(
|
||||
coords[i] for i in range(len(coords)) if i not in drop
|
||||
)
|
||||
glyph.flags = array.array(
|
||||
"B", (flags[i] for i in range(len(flags)) if i not in drop)
|
||||
)
|
||||
|
||||
endPts = glyph.endPtsOfContours
|
||||
newEndPts = []
|
||||
i = 0
|
||||
delta = 0
|
||||
for d in sorted(drop):
|
||||
while d > endPts[i]:
|
||||
newEndPts.append(endPts[i] - delta)
|
||||
i += 1
|
||||
delta += 1
|
||||
while i < len(endPts):
|
||||
newEndPts.append(endPts[i] - delta)
|
||||
i += 1
|
||||
glyph.flags = newFlags
|
||||
glyph.endPtsOfContours = newEndPts
|
||||
|
||||
return drop if drop is not None else set()
|
||||
|
@ -965,7 +965,7 @@ def test_dropImpliedOnCurvePoints_incompatible_number_of_contours():
|
||||
glyph2.flags = array.array("B", [1, 1, 1, 1])
|
||||
glyph2.coordinates = GlyphCoordinates([(0, 0), (1, 1), (2, 2), (3, 3)])
|
||||
|
||||
with pytest.raises(ValueError, match="Incompatible number of contours"):
|
||||
with pytest.raises(ValueError, match="Incompatible numberOfContours"):
|
||||
dropImpliedOnCurvePoints(glyph1, glyph2)
|
||||
|
||||
|
||||
@ -986,6 +986,23 @@ def test_dropImpliedOnCurvePoints_incompatible_flags():
|
||||
dropImpliedOnCurvePoints(glyph1, glyph2)
|
||||
|
||||
|
||||
def test_dropImpliedOnCurvePoints_incompatible_endPtsOfContours():
|
||||
glyph1 = Glyph()
|
||||
glyph1.numberOfContours = 2
|
||||
glyph1.endPtsOfContours = [2, 6]
|
||||
glyph1.flags = array.array("B", [1, 1, 1, 1, 1, 1, 1])
|
||||
glyph1.coordinates = GlyphCoordinates([(i, i) for i in range(7)])
|
||||
|
||||
glyph2 = Glyph()
|
||||
glyph2.numberOfContours = 2
|
||||
glyph2.endPtsOfContours = [3, 6]
|
||||
glyph2.flags = array.array("B", [1, 1, 1, 1, 1, 1, 1])
|
||||
glyph2.coordinates = GlyphCoordinates([(i, i) for i in range(7)])
|
||||
|
||||
with pytest.raises(ValueError, match="Incompatible endPtsOfContours"):
|
||||
dropImpliedOnCurvePoints(glyph1, glyph2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user