1use core::marker::PhantomData;
2use core::slice;
3use libc::{c_char, c_short};
4use {ffi, Vector};
5
6#[derive(Copy, Clone)]
7pub enum Curve {
8 Line(Vector),
9 Bezier2(Vector, Vector),
10 Bezier3(Vector, Vector, Vector),
11}
12
13pub struct Outline<'a> {
14 raw: &'a ffi::FT_Outline
15}
16
17impl<'a> Outline<'a> {
18 pub unsafe fn from_raw(raw: &'a ffi::FT_Outline) -> Self { Outline { raw } }
19
20 pub fn points(&self) -> &'a [Vector] {
21 unsafe { slice::from_raw_parts(self.raw.points, self.raw.n_points as usize) }
22 }
23
24 pub fn tags(&self) -> &'a [c_char] {
25 unsafe { slice::from_raw_parts(self.raw.tags, self.raw.n_points as usize) }
26 }
27
28 pub fn contours(&self) -> &'a [c_short] {
29 unsafe { slice::from_raw_parts(self.raw.contours, self.raw.n_contours as usize) }
30 }
31
32 pub fn contours_iter(&self) -> ContourIterator<'a> {
33 unsafe { ContourIterator::from_raw(self.raw) }
34 }
35}
36
37const TAG_ONCURVE: c_char = 0x01;
38const TAG_BEZIER3: c_char = 0x02;
39
40pub struct CurveIterator<'a> {
41 start_point: *const Vector,
42 start_tag: *const c_char,
43 idx: isize,
44 length: isize,
45 marker: PhantomData<&'a ()>
46}
47
48impl<'a> CurveIterator<'a> {
49 pub unsafe fn from_raw(outline: &'a ffi::FT_Outline, start_idx: isize, end_idx: isize) -> Self {
50 CurveIterator {
51 start_point: outline.points.offset(start_idx),
52 start_tag: outline.tags.offset(start_idx),
53 idx: 0,
54 length: end_idx - start_idx + 1,
55 marker: PhantomData
56 }
57 }
58
59 pub fn start(&self) -> &'a Vector {
60 unsafe { &*self.start_point }
61 }
62
63 unsafe fn pt(&self, i: isize) -> Vector {
66 if self.idx + i < self.length {
67 *self.start_point.offset(self.idx + i)
68 } else {
69 *self.start_point
70 }
71 }
72
73 unsafe fn tg(&self, i: isize) -> c_char {
74 if self.idx + i < self.length {
75 *self.start_tag.offset(self.idx + i)
76 } else {
77 *self.start_tag
78 }
79 }
80}
81
82impl<'a> Iterator for CurveIterator<'a> {
83 type Item = Curve;
84
85 fn next(&mut self) -> Option<Self::Item> {
86 if self.idx >= self.length {
87 None
88 } else {
89 unsafe {
90 let tag1 = self.tg(1);
91
92 let (shift, curve) = if (tag1 & TAG_ONCURVE) == TAG_ONCURVE {
93 (1, Curve::Line(self.pt(1)))
94 } else if (tag1 & TAG_BEZIER3) == TAG_BEZIER3 {
95 (3, Curve::Bezier3(self.pt(1), self.pt(2), self.pt(3)))
96 } else {
97 if (self.tg(2) & TAG_ONCURVE) == TAG_ONCURVE {
103 (2, Curve::Bezier2(self.pt(1), self.pt(2)))
104 } else {
105 let pt = ffi::FT_Vector {
106 x: (self.pt(1).x + self.pt(2).x) / 2,
107 y: (self.pt(1).y + self.pt(2).y) / 2,
108 };
109
110 (1, Curve::Bezier2(self.pt(1), pt))
111 }
112 };
113
114 self.idx += shift;
115 Some(curve)
116 }
117 }
118 }
119}
120
121pub struct ContourIterator<'a> {
122 outline: &'a ffi::FT_Outline,
123 contour_start: c_short,
124 contour_end_idx: *const c_short,
125 last_end_idx: *const c_short,
126}
127
128impl<'a> ContourIterator<'a> {
129 pub unsafe fn from_raw(outline: &'a ffi::FT_Outline) -> Self {
130 ContourIterator {
131 outline,
132 contour_start: 0,
133 contour_end_idx: outline.contours,
134 last_end_idx: outline.contours.offset(outline.n_contours as isize - 1),
135 }
136 }
137}
138
139impl<'a> Iterator for ContourIterator<'a> {
140 type Item = CurveIterator<'a>;
141
142 fn next(&mut self) -> Option<Self::Item> {
143 if self.contour_end_idx > self.last_end_idx {
144 None
145 } else {
146 unsafe {
147 let contour_end = *self.contour_end_idx;
148 let curves = CurveIterator::from_raw(self.outline, self.contour_start as isize,
149 contour_end as isize);
150 self.contour_start = contour_end + 1;
151 self.contour_end_idx = self.contour_end_idx.offset(1);
152
153 Some(curves)
154 }
155 }
156 }
157}