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

1from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect 

2from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds 

3from fontTools.pens.basePen import BasePen 

4 

5 

6__all__ = ["BoundsPen", "ControlBoundsPen"] 

7 

8 

9class ControlBoundsPen(BasePen): 

10 

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. 

15 

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:: 

18 

19 (xMin, yMin, xMax, yMax). 

20 

21 If ``ignoreSinglePoints`` is True, single points are ignored. 

22 """ 

23 

24 def __init__(self, glyphSet, ignoreSinglePoints=False): 

25 BasePen.__init__(self, glyphSet) 

26 self.ignoreSinglePoints = ignoreSinglePoints 

27 self.init() 

28 

29 def init(self): 

30 self.bounds = None 

31 self._start = None 

32 

33 def _moveTo(self, pt): 

34 self._start = pt 

35 if not self.ignoreSinglePoints: 

36 self._addMoveTo() 

37 

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 

48 

49 def _lineTo(self, pt): 

50 self._addMoveTo() 

51 self.bounds = updateBounds(self.bounds, pt) 

52 

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 

60 

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 

67 

68 

69class BoundsPen(ControlBoundsPen): 

70 

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". 

75 

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:: 

78 

79 (xMin, yMin, xMax, yMax) 

80 """ 

81 

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 

91 

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