Coverage for /usr/lib/python3/dist-packages/fontTools/pens/boundsPen.py: 27%
56 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect
2from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds
3from fontTools.pens.basePen import BasePen
6__all__ = ["BoundsPen", "ControlBoundsPen"]
9class ControlBoundsPen(BasePen):
11 """Pen to calculate the "control bounds" of a shape. This is the
12 bounding box of all control points, so may be larger than the
13 actual bounding box if there are curves that don't have points
14 on their extremes.
16 When the shape has been drawn, the bounds are available as the
17 ``bounds`` attribute of the pen object. It's a 4-tuple::
19 (xMin, yMin, xMax, yMax).
21 If ``ignoreSinglePoints`` is True, single points are ignored.
22 """
24 def __init__(self, glyphSet, ignoreSinglePoints=False):
25 BasePen.__init__(self, glyphSet)
26 self.ignoreSinglePoints = ignoreSinglePoints
27 self.init()
29 def init(self):
30 self.bounds = None
31 self._start = None
33 def _moveTo(self, pt):
34 self._start = pt
35 if not self.ignoreSinglePoints:
36 self._addMoveTo()
38 def _addMoveTo(self):
39 if self._start is None:
40 return
41 bounds = self.bounds
42 if bounds:
43 self.bounds = updateBounds(bounds, self._start)
44 else:
45 x, y = self._start
46 self.bounds = (x, y, x, y)
47 self._start = None
49 def _lineTo(self, pt):
50 self._addMoveTo()
51 self.bounds = updateBounds(self.bounds, pt)
53 def _curveToOne(self, bcp1, bcp2, pt):
54 self._addMoveTo()
55 bounds = self.bounds
56 bounds = updateBounds(bounds, bcp1)
57 bounds = updateBounds(bounds, bcp2)
58 bounds = updateBounds(bounds, pt)
59 self.bounds = bounds
61 def _qCurveToOne(self, bcp, pt):
62 self._addMoveTo()
63 bounds = self.bounds
64 bounds = updateBounds(bounds, bcp)
65 bounds = updateBounds(bounds, pt)
66 self.bounds = bounds
69class BoundsPen(ControlBoundsPen):
71 """Pen to calculate the bounds of a shape. It calculates the
72 correct bounds even when the shape contains curves that don't
73 have points on their extremes. This is somewhat slower to compute
74 than the "control bounds".
76 When the shape has been drawn, the bounds are available as the
77 ``bounds`` attribute of the pen object. It's a 4-tuple::
79 (xMin, yMin, xMax, yMax)
80 """
82 def _curveToOne(self, bcp1, bcp2, pt):
83 self._addMoveTo()
84 bounds = self.bounds
85 bounds = updateBounds(bounds, pt)
86 if not pointInRect(bcp1, bounds) or not pointInRect(bcp2, bounds):
87 bounds = unionRect(
88 bounds, calcCubicBounds(self._getCurrentPoint(), bcp1, bcp2, pt)
89 )
90 self.bounds = bounds
92 def _qCurveToOne(self, bcp, pt):
93 self._addMoveTo()
94 bounds = self.bounds
95 bounds = updateBounds(bounds, pt)
96 if not pointInRect(bcp, bounds):
97 bounds = unionRect(
98 bounds, calcQuadraticBounds(self._getCurrentPoint(), bcp, pt)
99 )
100 self.bounds = bounds