swash/scale/
outline.rs

1/*!
2Glyph outline.
3*/
4
5use alloc::vec::Vec;
6use zeno::{Bounds, PathData, Point, Transform, Verb};
7
8/// Scaled glyph outline represented as a collection of layers and a sequence
9/// of points and verbs.
10#[derive(Clone, Default)]
11pub struct Outline {
12    layers: Vec<LayerData>,
13    points: Vec<Point>,
14    verbs: Vec<Verb>,
15    is_color: bool,
16}
17
18impl Outline {
19    /// Creates a new empty outline.
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Returns true if the outline has color layers.
25    pub fn is_color(&self) -> bool {
26        self.is_color
27    }
28
29    /// Returns the number of layers in the outline.
30    pub fn len(&self) -> usize {
31        self.layers.len()
32    }
33
34    /// Returns true if there are no layers in the outline.
35    pub fn is_empty(&self) -> bool {
36        self.layers.is_empty()
37    }
38
39    /// Returns a reference to the layer at the specified index.
40    pub fn get<'a>(&'a self, index: usize) -> Option<Layer<'a>> {
41        let data = self.layers.get(index)?;
42        let points = self.points.get(data.points.0..data.points.1)?;
43        let verbs = self.verbs.get(data.verbs.0..data.verbs.1)?;
44        let color_index = data.color_index;
45        Some(Layer {
46            points,
47            verbs,
48            color_index,
49        })
50    }
51
52    /// Returns a mutable reference to the layer at the specified index.
53    pub fn get_mut<'a>(&'a mut self, index: usize) -> Option<LayerMut<'a>> {
54        let data = self.layers.get(index)?;
55        let points = self.points.get_mut(data.points.0..data.points.1)?;
56        let verbs = self.verbs.get(data.verbs.0..data.verbs.1)?;
57        let color_index = data.color_index;
58        Some(LayerMut {
59            points,
60            verbs,
61            color_index,
62        })
63    }
64
65    /// Returns a reference to the sequence of points in the outline.
66    pub fn points(&self) -> &[Point] {
67        &self.points
68    }
69
70    /// Returns a mutable reference to the sequence of points in the outline.
71    pub fn points_mut(&mut self) -> &mut [Point] {
72        &mut self.points
73    }
74
75    /// Returns a reference to the sequence of verbs in the outline.
76    pub fn verbs(&self) -> &[Verb] {
77        &self.verbs
78    }
79
80    /// Returns path data for the outline.
81    pub fn path(&self) -> impl PathData + '_ {
82        (&self.points[..], &self.verbs[..])
83    }
84
85    /// Computes the bounding box of the outline.
86    pub fn bounds(&self) -> Bounds {
87        Bounds::from_points(&self.points)
88    }
89
90    /// Transforms the outline by the specified matrix.
91    pub fn transform(&mut self, transform: &Transform) {
92        for p in &mut self.points {
93            *p = transform.transform_point(*p);
94        }
95    }
96
97    /// Applies a faux bold to the outline with the specified strengths in the
98    /// x and y directions.
99    pub fn embolden(&mut self, x_strength: f32, y_strength: f32) {
100        for i in 0..self.len() {
101            if let Some(mut layer) = self.get_mut(i) {
102                layer.embolden(x_strength, y_strength);
103            }
104        }
105    }
106
107    /// Clears the outline.
108    pub fn clear(&mut self) {
109        self.points.clear();
110        self.verbs.clear();
111        self.layers.clear();
112        self.is_color = false;
113    }
114}
115
116/// Reference to a layer in a scaled outline.
117#[derive(Copy, Clone)]
118pub struct Layer<'a> {
119    points: &'a [Point],
120    verbs: &'a [Verb],
121    color_index: Option<u16>,
122}
123
124impl<'a> Layer<'a> {
125    /// Returns the sequence of points for the layer.
126    pub fn points(&self) -> &'a [Point] {
127        self.points
128    }
129
130    /// Returns the sequence of verbs for the layer.
131    pub fn verbs(&self) -> &'a [Verb] {
132        self.verbs
133    }
134
135    /// Returns path data for the layer.
136    pub fn path(&self) -> impl PathData + 'a {
137        (self.points(), self.verbs())
138    }
139
140    /// Computes the bounding box of the layer.
141    pub fn bounds(&self) -> Bounds {
142        Bounds::from_points(self.points())
143    }
144
145    /// Returns the color index for the layer.
146    pub fn color_index(&self) -> Option<u16> {
147        self.color_index
148    }
149}
150
151/// Mutable reference to a layer in a scaled outline.
152pub struct LayerMut<'a> {
153    points: &'a mut [Point],
154    verbs: &'a [Verb],
155    color_index: Option<u16>,
156}
157
158impl<'a> LayerMut<'a> {
159    /// Returns the sequence of points for the layer.
160    pub fn points(&'a self) -> &'a [Point] {
161        self.points
162    }
163
164    /// Returns a mutable reference the sequence of points for the layer.
165    pub fn points_mut(&'a mut self) -> &'a mut [Point] {
166        &mut *self.points
167    }
168
169    /// Returns the sequence of verbs for the layer.
170    pub fn verbs(&self) -> &'a [Verb] {
171        self.verbs
172    }
173
174    /// Returns path data for the layer.
175    pub fn path(&'a self) -> impl PathData + 'a {
176        (self.points(), self.verbs())
177    }
178
179    /// Computes the bounding box of the layer.
180    pub fn bounds(&self) -> Bounds {
181        Bounds::from_points(self.points())
182    }
183
184    /// Returns the color index for the layer.
185    pub fn color_index(&self) -> Option<u16> {
186        self.color_index
187    }
188    /// Transforms this layer by the specified matrix.
189    pub fn transform(&'a mut self, transform: &Transform) {
190        for p in self.points.iter_mut() {
191            *p = transform.transform_point(*p);
192        }
193    }
194
195    /// Applies a faux bold to this layer with the specified strengths in the
196    /// x and y directions.
197    pub fn embolden(&mut self, x_strength: f32, y_strength: f32) {
198        let mut point_start = 0;
199        let mut pos = 0;
200        let winding = compute_winding(self.points);
201        for verb in self.verbs {
202            match verb {
203                Verb::MoveTo | Verb::Close => {
204                    if let Some(points) = self.points.get_mut(point_start..pos) {
205                        if !points.is_empty() {
206                            embolden(points, winding, x_strength, y_strength);
207                        }
208                        point_start = pos;
209                        if *verb == Verb::MoveTo {
210                            pos += 1;
211                        }
212                    } else {
213                        return;
214                    }
215                }
216                Verb::LineTo => pos += 1,
217                Verb::QuadTo => pos += 2,
218                Verb::CurveTo => pos += 3,
219            }
220        }
221        if pos > point_start {
222            if let Some(points) = self.points.get_mut(point_start..pos) {
223                embolden(points, winding, x_strength, y_strength);
224            }
225        }
226    }
227}
228
229#[derive(Copy, Clone, Default)]
230struct LayerData {
231    points: (usize, usize),
232    verbs: (usize, usize),
233    color_index: Option<u16>,
234}
235
236impl Outline {
237    pub(super) fn set_color(&mut self, color: bool) {
238        self.is_color = color;
239    }
240
241    pub(super) fn move_to(&mut self, p: Point) {
242        self.maybe_close();
243        self.points.push(p);
244        self.verbs.push(Verb::MoveTo);
245    }
246
247    pub(super) fn line_to(&mut self, p: Point) {
248        self.points.push(p);
249        self.verbs.push(Verb::LineTo);
250    }
251
252    pub(super) fn quad_to(&mut self, p0: Point, p1: Point) {
253        self.points.push(p0);
254        self.points.push(p1);
255        self.verbs.push(Verb::QuadTo);
256    }
257
258    pub(super) fn curve_to(&mut self, p0: Point, p1: Point, p2: Point) {
259        self.points.push(p0);
260        self.points.push(p1);
261        self.points.push(p2);
262        self.verbs.push(Verb::CurveTo);
263    }
264
265    pub(super) fn close(&mut self) {
266        self.verbs.push(Verb::Close);
267    }
268
269    pub(super) fn maybe_close(&mut self) {
270        if !self.verbs.is_empty() && self.verbs.last() != Some(&Verb::Close) {
271            self.close();
272        }
273    }
274
275    pub(super) fn begin_layer(&mut self, color_index: Option<u16>) {
276        let points_end = self.points.len();
277        let verbs_end = self.verbs.len();
278        if let Some(last) = self.layers.last_mut() {
279            last.points.1 = points_end;
280            last.verbs.1 = verbs_end;
281        }
282        self.layers.push(LayerData {
283            points: (points_end, points_end),
284            verbs: (verbs_end, verbs_end),
285            color_index,
286        });
287    }
288
289    pub(super) fn finish(&mut self) {
290        let points_end = self.points.len();
291        let verbs_end = self.verbs.len();
292        if let Some(last) = self.layers.last_mut() {
293            last.points.1 = points_end;
294            last.verbs.1 = verbs_end;
295        } else {
296            self.layers.push(LayerData {
297                points: (0, points_end),
298                verbs: (0, verbs_end),
299                color_index: None,
300            });
301        }
302    }
303}
304
305fn embolden(points: &mut [Point], winding: u8, x_strength: f32, y_strength: f32) {
306    if points.is_empty() {
307        return;
308    }
309    let last = points.len() - 1;
310    let mut i = last;
311    let mut j = 0;
312    let mut k = !0;
313    let mut out_len;
314    let mut in_len = 0.;
315    let mut anchor_len = 0.;
316    let mut anchor = Point::ZERO;
317    let mut out;
318    let mut in_ = Point::ZERO;
319    while j != i && i != k {
320        if j != k {
321            out = points[j] - points[i];
322            out_len = out.length();
323            if out_len == 0. {
324                j = if j < last { j + 1 } else { 0 };
325                continue;
326            } else {
327                let s = 1. / out_len;
328                out.x *= s;
329                out.y *= s;
330            }
331        } else {
332            out = anchor;
333            out_len = anchor_len;
334        }
335        if in_len != 0. {
336            if k == !0 {
337                k = i;
338                anchor = in_;
339                anchor_len = in_len;
340            }
341            let mut d = (in_.x * out.x) + (in_.y * out.y);
342            let shift = if d > -0.9396 {
343                d += 1.;
344                let mut sx = in_.y + out.y;
345                let mut sy = in_.x + out.x;
346                if winding == 0 {
347                    sx = -sx;
348                } else {
349                    sy = -sy;
350                }
351                let mut q = (out.x * in_.y) - (out.y * in_.x);
352                if winding == 0 {
353                    q = -q;
354                }
355                let l = in_len.min(out_len);
356                if x_strength * q <= l * d {
357                    sx = sx * x_strength / d;
358                } else {
359                    sx = sx * l / q;
360                }
361                if y_strength * q <= l * d {
362                    sy = sy * y_strength / d;
363                } else {
364                    sy = sy * l / q;
365                }
366                Point::new(sx, sy)
367            } else {
368                Point::ZERO
369            };
370
371            while i != j {
372                points[i].x += x_strength + shift.x;
373                points[i].y += y_strength + shift.y;
374                i = if i < last { i + 1 } else { 0 };
375            }
376        } else {
377            i = j;
378        }
379        in_ = out;
380        in_len = out_len;
381        j = if j < last { j + 1 } else { 0 };
382    }
383}
384
385fn compute_winding(points: &[Point]) -> u8 {
386    if points.is_empty() {
387        return 0;
388    }
389    let mut area = 0.;
390    let last = points.len() - 1;
391    let mut prev = points[last];
392    for cur in points[0..=last].iter() {
393        area += (cur.y - prev.y) * (cur.x + prev.x);
394        prev = *cur;
395    }
396    if area > 0. {
397        1
398    } else {
399        0
400    }
401}
402
403impl skrifa::outline::OutlinePen for Outline {
404    fn move_to(&mut self, x: f32, y: f32) {
405        self.move_to((x, y).into());
406    }
407
408    fn line_to(&mut self, x: f32, y: f32) {
409        self.line_to((x, y).into());
410    }
411
412    fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) {
413        self.quad_to((cx0, cy0).into(), (x, y).into());
414    }
415
416    fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) {
417        self.curve_to((cx0, cy0).into(), (cx1, cy1).into(), (x, y).into());
418    }
419
420    fn close(&mut self) {
421        self.close();
422    }
423}