1use crate::fearless_simd::Level;
7use crate::flatten::{FlattenCtx, Line};
8use crate::kurbo::{Affine, PathEl, Stroke};
9use crate::peniko::Fill;
10use crate::strip::Strip;
11use crate::tile::Tiles;
12use crate::{flatten, strip};
13use alloc::vec::Vec;
14use peniko::kurbo::StrokeCtx;
15
16#[derive(Debug, Default)]
18pub struct StripStorage {
19 pub strips: Vec<Strip>,
21 pub alphas: Vec<u8>,
23 generation_mode: GenerationMode,
24}
25
26#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
28pub enum GenerationMode {
29 #[default]
30 Replace,
32 Append,
34}
35
36impl StripStorage {
37 pub fn clear(&mut self) {
39 self.strips.clear();
40 self.alphas.clear();
41 }
42
43 pub fn set_generation_mode(&mut self, mode: GenerationMode) {
45 self.generation_mode = mode;
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.strips.is_empty() && self.alphas.is_empty()
51 }
52}
53
54#[derive(Debug)]
56pub struct StripGenerator {
57 level: Level,
58 line_buf: Vec<Line>,
59 flatten_ctx: FlattenCtx,
60 stroke_ctx: StrokeCtx,
61 tiles: Tiles,
62 width: u16,
63 height: u16,
64}
65
66impl StripGenerator {
67 pub fn new(width: u16, height: u16, level: Level) -> Self {
69 Self {
70 level,
71 line_buf: Vec::new(),
72 tiles: Tiles::new(level),
73 flatten_ctx: FlattenCtx::default(),
74 stroke_ctx: StrokeCtx::default(),
75 width,
76 height,
77 }
78 }
79
80 pub fn generate_filled_path(
82 &mut self,
83 path: impl IntoIterator<Item = PathEl>,
84 fill_rule: Fill,
85 transform: Affine,
86 aliasing_threshold: Option<u8>,
87 strip_storage: &mut StripStorage,
88 ) {
89 flatten::fill(
90 self.level,
91 path,
92 transform,
93 &mut self.line_buf,
94 &mut self.flatten_ctx,
95 );
96 self.make_strips(strip_storage, fill_rule, aliasing_threshold);
97 }
98
99 pub fn generate_stroked_path(
101 &mut self,
102 path: impl IntoIterator<Item = PathEl>,
103 stroke: &Stroke,
104 transform: Affine,
105 aliasing_threshold: Option<u8>,
106 strip_storage: &mut StripStorage,
107 ) {
108 flatten::stroke(
109 self.level,
110 path,
111 stroke,
112 transform,
113 &mut self.line_buf,
114 &mut self.flatten_ctx,
115 &mut self.stroke_ctx,
116 );
117 self.make_strips(strip_storage, Fill::NonZero, aliasing_threshold);
118 }
119
120 pub fn reset(&mut self) {
122 self.line_buf.clear();
123 self.tiles.reset();
124 }
125
126 fn make_strips(
127 &mut self,
128 strip_storage: &mut StripStorage,
129 fill_rule: Fill,
130 aliasing_threshold: Option<u8>,
131 ) {
132 self.tiles
133 .make_tiles(&self.line_buf, self.width, self.height);
134 self.tiles.sort_tiles();
135
136 if strip_storage.generation_mode == GenerationMode::Replace {
137 strip_storage.strips.clear();
138 }
139
140 strip::render(
141 self.level,
142 &self.tiles,
143 &mut strip_storage.strips,
144 &mut strip_storage.alphas,
145 fill_rule,
146 aliasing_threshold,
147 &self.line_buf,
148 );
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use crate::fearless_simd::Level;
155 use crate::kurbo::{Affine, Rect, Shape};
156 use crate::peniko::Fill;
157 use crate::strip_generator::{StripGenerator, StripStorage};
158
159 #[test]
160 fn reset() {
161 let mut generator = StripGenerator::new(100, 100, Level::fallback());
162 let mut storage = StripStorage::default();
163 let rect = Rect::new(0.0, 0.0, 100.0, 100.0);
164
165 generator.generate_filled_path(
166 rect.to_path(0.1),
167 Fill::NonZero,
168 Affine::IDENTITY,
169 None,
170 &mut storage,
171 );
172
173 assert!(!generator.line_buf.is_empty());
174 assert!(!storage.is_empty());
175
176 generator.reset();
177 storage.clear();
178
179 assert!(generator.line_buf.is_empty());
180 assert!(storage.is_empty());
181 }
182}