@@ -46,9 +46,19 @@ impl<'a> Outline<'a> {
46
46
}
47
47
}
48
48
49
+ const TAG_MASK : c_char = 0x03 ;
49
50
const TAG_ONCURVE : c_char = 0x01 ;
51
+ const TAG_BEZIER2 : c_char = 0x00 ;
50
52
const TAG_BEZIER3 : c_char = 0x02 ;
51
53
54
+ #[ inline]
55
+ fn middle_point ( pt1 : Vector , pt2 : Vector ) -> Vector {
56
+ ffi:: FT_Vector {
57
+ x : ( pt1. x + pt2. x ) / 2 ,
58
+ y : ( pt1. y + pt2. y ) / 2 ,
59
+ }
60
+ }
61
+
52
62
pub struct CurveIterator < ' a > {
53
63
start_point : * const Vector ,
54
64
start_tag : * const c_char ,
@@ -64,15 +74,27 @@ impl<'a> CurveIterator<'a> {
64
74
CurveIterator {
65
75
start_point : outline. points . offset ( start_idx) ,
66
76
start_tag : outline. tags . offset ( start_idx) ,
67
- idx : 0 ,
77
+ // If the first tag is off-curve, start at -1 and return last or interpolated point as start()
78
+ idx : if * outline. tags . offset ( start_idx) & TAG_MASK == TAG_BEZIER2 { -1 } else { 0 } ,
68
79
length : end_idx - start_idx + 1 ,
69
80
marker : PhantomData
70
81
}
71
82
}
72
83
73
- pub fn start ( & self ) -> & ' a Vector {
84
+ pub fn start ( & self ) -> Vector {
74
85
unsafe {
75
- & * self . start_point
86
+ // Check if starting point is off-curve, use last point in that case
87
+ if * self . start_tag & TAG_MASK == TAG_BEZIER2 {
88
+ match * self . start_tag . offset ( self . length - 1 ) {
89
+ TAG_ONCURVE => * self . start_point . offset ( self . length - 1 ) ,
90
+ // If last point is also off-curve, then interpolate
91
+ TAG_BEZIER2 => middle_point ( * self . start_point . offset ( self . length - 1 ) ,
92
+ * self . start_point ) ,
93
+ _ => panic ! ( "Unexpected curve tag" ) ,
94
+ }
95
+ } else {
96
+ * self . start_point
97
+ }
76
98
}
77
99
}
78
100
@@ -103,28 +125,35 @@ impl<'a> Iterator for CurveIterator<'a> {
103
125
None
104
126
} else {
105
127
unsafe {
106
- let tag1 = self . tg ( 1 ) ;
107
-
108
- let ( shift, curve) = if ( tag1 & TAG_ONCURVE ) == TAG_ONCURVE {
109
- ( 1 , Curve :: Line ( self . pt ( 1 ) ) )
110
- } else if ( tag1 & TAG_BEZIER3 ) == TAG_BEZIER3 {
111
- ( 3 , Curve :: Bezier3 ( self . pt ( 1 ) , self . pt ( 2 ) , self . pt ( 3 ) ) )
112
- } else {
113
- // We are some kind of quadratic Bezier.
114
- // Quadratic Bezier curves have a special treatment in TTF outlines:
115
- // as an optimization, curves are often constructed from sequences
116
- // of off-curve control points. In this case, there are implied on-curve
117
- // points in between each pair of off-curve points.
118
- if ( self . tg ( 2 ) & TAG_ONCURVE ) == TAG_ONCURVE {
119
- ( 2 , Curve :: Bezier2 ( self . pt ( 1 ) , self . pt ( 2 ) ) )
120
- } else {
121
- let pt = ffi:: FT_Vector {
122
- x : ( self . pt ( 1 ) . x + self . pt ( 2 ) . x ) / 2 ,
123
- y : ( self . pt ( 1 ) . y + self . pt ( 2 ) . y ) / 2 ,
124
- } ;
125
-
126
- ( 1 , Curve :: Bezier2 ( self . pt ( 1 ) , pt) )
127
- }
128
+ let ( shift, curve) =
129
+ match self . tg ( 1 ) {
130
+ TAG_ONCURVE => ( 1 , Curve :: Line ( self . pt ( 1 ) ) ) ,
131
+ TAG_BEZIER2 => {
132
+ // We are some kind of quadratic Bezier.
133
+ // Quadratic Bezier curves have a special treatment in TTF outlines:
134
+ // as an optimization, curves are often constructed from sequences
135
+ // of off-curve control points. In this case, there are implied on-curve
136
+ // points in between each pair of off-curve points.
137
+
138
+ // If we are at last point and checking first point (in circular fashion),
139
+ // and it's off-curve, then stop iterating. The last point was already
140
+ // reported by start() method.
141
+ if self . idx == self . length - 1 {
142
+ return None ;
143
+ }
144
+
145
+ match self . tg ( 2 ) {
146
+ TAG_ONCURVE => ( 2 , Curve :: Bezier2 ( self . pt ( 1 ) , self . pt ( 2 ) ) ) ,
147
+ TAG_BEZIER2 => ( 1 , Curve :: Bezier2 ( self . pt ( 1 ) , middle_point ( self . pt ( 1 ) , self . pt ( 2 ) ) ) ) ,
148
+ _ => panic ! ( "Unexpected curve tag" ) ,
149
+ }
150
+ } ,
151
+ TAG_BEZIER3 => {
152
+ debug_assert ! ( self . tg( 2 ) == TAG_BEZIER3 ) ;
153
+ debug_assert ! ( self . tg( 3 ) == TAG_ONCURVE ) ;
154
+ ( 3 , Curve :: Bezier3 ( self . pt ( 1 ) , self . pt ( 2 ) , self . pt ( 3 ) ) )
155
+ } ,
156
+ _ => panic ! ( "Unexpected curve tag" ) ,
128
157
} ;
129
158
130
159
self . idx += shift;
0 commit comments