1#![allow(clippy::too_many_arguments)]
2
3// This module contains a few helpers that should not be considered as part of the public API,
4// but are exposed for use by other lyon crates.
5// Changing them doesn't necessarily imply semver breaking bumps.
6
7pub use crate::geom::{CubicBezierSegment, QuadraticBezierSegment};
8pub use crate::math::Point;
9pub use crate::traits::PathBuilder;
10pub use crate::{Attributes, EndpointId};
11
12#[derive(Default, Copy, Clone, Debug, PartialEq)]
13pub struct DebugValidator {
14 #[cfg(debug_assertions)]
15 in_subpath: bool,
16}
17
18impl DebugValidator {
19 #[inline(always)]
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 #[inline(always)]
25 pub fn begin(&mut self) {
26 #[cfg(debug_assertions)]
27 {
28 assert!(!self.in_subpath, "multiple begin() calls without end()");
29 self.in_subpath = true;
30 }
31 }
32
33 #[inline(always)]
34 pub fn end(&mut self) {
35 #[cfg(debug_assertions)]
36 {
37 assert!(self.in_subpath, "end() called without begin()");
38 self.in_subpath = false;
39 }
40 }
41
42 #[inline(always)]
43 pub fn edge(&self) {
44 #[cfg(debug_assertions)]
45 assert!(self.in_subpath, "edge operation is made before begin()");
46 }
47
48 /// TODO: this should consume `self` to ensure it is dropped after this call
49 /// TODO: also, DebugValidator probably should not be exposed in the public API.
50 #[inline(always)]
51 pub fn build(&self) {
52 #[cfg(debug_assertions)]
53 assert!(!self.in_subpath, "build() called before end()");
54 }
55}
56
57pub fn flatten_quadratic_bezier(
58 tolerance: f32,
59 from: Point,
60 ctrl: Point,
61 to: Point,
62 attributes: Attributes,
63 prev_attributes: Attributes,
64 builder: &mut impl PathBuilder,
65 buffer: &mut [f32],
66) -> EndpointId {
67 let curve: QuadraticBezierSegment = QuadraticBezierSegment { from, ctrl, to };
68 let n: usize = attributes.len();
69 let mut id: EndpointId = EndpointId::INVALID;
70 curve.for_each_flattened_with_t(tolerance, &mut |line: &LineSegment, t: Range| {
71 let attr: &[f32] = if t.end == 1.0 {
72 attributes
73 } else {
74 for i: usize in 0..n {
75 buffer[i] = prev_attributes[i] * (1.0 - t.end) + attributes[i] * t.end;
76 }
77 // BUG: https://github.com/rust-lang/rust-clippy/issues/10608
78 #[allow(clippy::redundant_slicing)]
79 &buffer[..]
80 };
81 id = builder.line_to(line.to, custom_attributes:attr);
82 });
83
84 id
85}
86
87pub fn flatten_cubic_bezier(
88 tolerance: f32,
89 from: Point,
90 ctrl1: Point,
91 ctrl2: Point,
92 to: Point,
93 attributes: Attributes,
94 prev_attributes: Attributes,
95 builder: &mut impl PathBuilder,
96 buffer: &mut [f32],
97) -> EndpointId {
98 let curve = CubicBezierSegment {
99 from,
100 ctrl1,
101 ctrl2,
102 to,
103 };
104 let n = attributes.len();
105 let mut id = EndpointId::INVALID;
106 curve.for_each_flattened_with_t(tolerance, &mut |line, t| {
107 let attr = if t.end == 1.0 {
108 attributes
109 } else {
110 for i in 0..n {
111 buffer[i] = prev_attributes[i] * (1.0 - t.end) + attributes[i] * t.end;
112 }
113 // BUG: https://github.com/rust-lang/rust-clippy/issues/10608
114 #[allow(clippy::redundant_slicing)]
115 &buffer[..]
116 };
117 id = builder.line_to(line.to, attr);
118 });
119
120 id
121}
122