1use super::geometry::{Origin, Placement, Transform, Vector};
4use super::path_data::{apply, PathData};
5use super::scratch::Scratch;
6use super::style::{Fill, Style};
7#[allow(unused)]
8use super::F32Ext;
9
10use crate::lib::Vec;
11use core::cell::RefCell;
12
13#[derive(Copy, Clone, PartialEq, Debug)]
15pub enum Format {
16 Alpha,
18 Subpixel,
21 CustomSubpixel([f32; 3]),
23}
24
25impl Format {
26 pub fn subpixel_bgra() -> Self {
28 Self::CustomSubpixel([0.3, 0., -0.3])
29 }
30
31 pub fn buffer_size(self, width: u32, height: u32) -> usize {
34 (width
35 * height
36 * match self {
37 Self::Alpha => 1,
38 _ => 4,
39 }) as usize
40 }
41}
42
43impl Default for Format {
44 fn default() -> Self {
45 Self::Alpha
46 }
47}
48
49pub struct Mask<'a, 's, D> {
51 data: D,
52 style: Style<'a>,
53 transform: Option<Transform>,
54 format: Format,
55 origin: Origin,
56 offset: Vector,
57 render_offset: Vector,
58 width: u32,
59 height: u32,
60 explicit_size: bool,
61 has_size: bool,
62 bounds_offset: Vector,
63 scratch: RefCell<Option<&'s mut Scratch>>,
64}
65
66impl<'a, 's, D> Mask<'a, 's, D>
67where
68 D: PathData,
69{
70 pub fn new(data: D) -> Self {
72 Self {
73 data,
74 style: Style::Fill(Fill::NonZero),
75 transform: None,
76 format: Format::Alpha,
77 origin: Origin::TopLeft,
78 offset: Vector::ZERO,
79 render_offset: Vector::ZERO,
80 width: 0,
81 height: 0,
82 explicit_size: false,
83 has_size: false,
84 bounds_offset: Vector::ZERO,
85 scratch: RefCell::new(None),
86 }
87 }
88
89 pub fn with_scratch(data: D, scratch: &'s mut Scratch) -> Self {
91 Self {
92 data,
93 style: Style::Fill(Fill::NonZero),
94 transform: None,
95 format: Format::Alpha,
96 origin: Origin::TopLeft,
97 offset: Vector::ZERO,
98 render_offset: Vector::ZERO,
99 width: 0,
100 height: 0,
101 explicit_size: false,
102 has_size: false,
103 bounds_offset: Vector::ZERO,
104 scratch: RefCell::new(Some(scratch)),
105 }
106 }
107
108 pub fn style(&mut self, style: impl Into<Style<'a>>) -> &mut Self {
110 self.style = style.into();
111 self
112 }
113
114 pub fn transform(&mut self, transform: Option<Transform>) -> &mut Self {
116 self.transform = transform;
117 self
118 }
119
120 pub fn format(&mut self, format: Format) -> &mut Self {
123 self.format = format;
124 self
125 }
126
127 pub fn origin(&mut self, origin: Origin) -> &mut Self {
129 self.origin = origin;
130 self
131 }
132
133 pub fn offset(&mut self, offset: impl Into<Vector>) -> &mut Self {
137 self.offset = offset.into();
138 self
139 }
140
141 pub fn size(&mut self, width: u32, height: u32) -> &mut Self {
145 self.width = width;
146 self.height = height;
147 self.explicit_size = true;
148 self.has_size = true;
149 self
150 }
151
152 pub fn render_offset(&mut self, offset: impl Into<Vector>) -> &mut Self {
156 self.render_offset = offset.into();
157 self
158 }
159
160 pub fn inspect(&mut self, mut f: impl FnMut(Format, u32, u32)) -> &mut Self {
164 self.ensure_size();
165 f(self.format, self.width, self.height);
166 self
167 }
168
169 pub fn render_into(&self, buffer: &mut [u8], pitch: Option<usize>) -> Placement {
175 let (offset, placement) = self.placement();
176 let pitch = match pitch {
177 Some(pitch) => pitch,
178 _ => {
179 placement.width as usize
180 * match self.format {
181 Format::Alpha => 1,
182 _ => 4,
183 }
184 }
185 };
186 render(self, offset, &placement, buffer, pitch);
187 placement
188 }
189
190 pub fn render(&self) -> (Vec<u8>, Placement) {
192 let mut buf = Vec::new();
193 let (offset, placement) = self.placement();
194 buf.resize(
195 self.format.buffer_size(placement.width, placement.height),
196 0,
197 );
198 let pitch = placement.width as usize
199 * match self.format {
200 Format::Alpha => 1,
201 _ => 4,
202 };
203 render(self, offset, &placement, &mut buf, pitch);
204 (buf, placement)
205 }
206
207 fn ensure_size(&mut self) {
208 if self.has_size {
209 return;
210 }
211 let (offset, placement) = self.placement();
212 self.bounds_offset = offset;
213 self.width = placement.width;
214 self.height = placement.height;
215 self.explicit_size = false;
216 self.has_size = true;
217 }
218
219 fn placement(&self) -> (Vector, Placement) {
220 let mut placement = Placement {
221 left: 0,
222 top: 0,
223 width: self.width,
224 height: self.height,
225 };
226 let mut offset = self.offset;
227 if self.explicit_size {
228 return (offset, placement);
229 } else if !self.has_size {
230 let mut scratch = self.scratch.borrow_mut();
231 let mut bounds = if let Some(scratch) = scratch.as_mut() {
232 scratch.bounds(&self.data, self.style, self.transform)
233 } else {
234 super::bounds(&self.data, self.style, self.transform)
235 };
236 bounds.min = (bounds.min + self.offset).floor();
237 bounds.max = (bounds.max + self.offset).ceil();
238 offset = Vector::new(-bounds.min.x, -bounds.min.y);
239 placement.width = bounds.width() as u32;
240 placement.height = bounds.height() as u32;
241 } else {
242 offset = self.bounds_offset;
243 }
244 placement.left = -offset.x as i32;
245 placement.top = if self.origin == Origin::BottomLeft {
246 (-offset.y).floor() + self.height as f32
247 } else {
248 -offset.y
249 } as i32;
250 (offset, placement)
251 }
252}
253
254#[allow(clippy::needless_lifetimes)]
255pub fn render<'a, 'c, D>(
256 mask: &'a Mask<'a, 'c, D>,
257 offset: Vector,
258 placement: &Placement,
259 buf: &mut [u8],
260 pitch: usize,
261) where
262 D: PathData,
263{
264 let y_up = mask.origin == Origin::BottomLeft;
265 let (is_subpx, subpx) = match mask.format {
266 Format::Alpha => (false, [Vector::ZERO; 3]),
267 Format::Subpixel => (
268 true,
269 [Vector::new(-0.3, 0.), Vector::ZERO, Vector::new(0.3, 0.)],
270 ),
271 Format::CustomSubpixel(subpx) => (
272 true,
273 [
274 Vector::new(subpx[0], 0.),
275 Vector::new(subpx[1], 0.),
276 Vector::new(subpx[2], 0.),
277 ],
278 ),
279 };
280 let fill = match mask.style {
281 Style::Fill(fill) => fill,
282 _ => Fill::NonZero,
283 };
284 let w = placement.width;
285 let h = placement.height;
286 let shift = offset + mask.render_offset;
287 let data = &mask.data;
288 let style = mask.style;
289 let transform = mask.transform;
290 let mut scratch = mask.scratch.borrow_mut();
291 use super::raster::{AdaptiveStorage, Rasterizer};
292 if let Some(scratch) = scratch.as_mut() {
293 let mut ras = Rasterizer::new(&mut scratch.render);
294 let inner = &mut scratch.inner;
295 if is_subpx {
296 ras.rasterize_write(
297 shift + subpx[0],
298 w,
299 h,
300 &mut |r| {
301 inner.apply(data, &style, transform, r);
302 },
303 fill,
304 pitch,
305 y_up,
306 &mut |row_offset, x, count, coverage| {
307 let buf = &mut buf[row_offset..];
308 let mut i = 0;
309 let mut j = x * 4;
310 while i < count {
311 buf[j] = coverage;
312 i += 1;
313 j += 4;
314 }
315 },
316 );
317 ras.rasterize_write(
318 shift + subpx[1],
319 w,
320 h,
321 &mut |r| {
322 inner.apply(data, &style, transform, r);
323 },
324 fill,
325 pitch,
326 y_up,
327 &mut |row_offset, x, count, coverage| {
328 let buf = &mut buf[row_offset..];
329 let mut i = 0;
330 let mut j = x * 4 + 1;
331 while i < count {
332 buf[j] = coverage;
333 i += 1;
334 j += 4;
335 }
336 },
337 );
338 ras.rasterize_write(
339 shift + subpx[2],
340 w,
341 h,
342 &mut |r| {
343 inner.apply(data, &style, transform, r);
344 },
345 fill,
346 pitch,
347 y_up,
348 &mut |row_offset, x, count, coverage| {
349 let buf = &mut buf[row_offset..];
350 let mut i = 0;
351 let mut j = x * 4 + 2;
352 while i < count {
353 buf[j] = coverage;
354 i += 1;
355 j += 4;
356 }
357 },
358 );
359 } else {
360 ras.rasterize(
361 shift,
362 w,
363 h,
364 &mut |r| {
365 inner.apply(data, &style, transform, r);
366 },
367 fill,
368 buf,
369 pitch,
370 y_up,
371 );
372 }
373 } else {
374 let mut storage = AdaptiveStorage::new();
375 let mut ras = Rasterizer::new(&mut storage);
376 if is_subpx {
377 ras.rasterize_write(
378 shift + subpx[0],
379 w,
380 h,
381 &mut |r| {
382 apply(data, style, transform, r);
383 },
384 fill,
385 pitch,
386 y_up,
387 &mut |row_offset, x, count, coverage| {
388 let buf = &mut buf[row_offset..];
389 let mut i = 0;
390 let mut j = x * 4;
391 while i < count {
392 buf[j] = coverage;
393 i += 1;
394 j += 4;
395 }
396 },
397 );
398 ras.rasterize_write(
399 shift + subpx[1],
400 w,
401 h,
402 &mut |r| {
403 apply(data, style, transform, r);
404 },
405 fill,
406 pitch,
407 y_up,
408 &mut |row_offset, x, count, coverage| {
409 let buf = &mut buf[row_offset..];
410 let mut i = 0;
411 let mut j = x * 4 + 1;
412 while i < count {
413 buf[j] = coverage;
414 i += 1;
415 j += 4;
416 }
417 },
418 );
419 ras.rasterize_write(
420 shift + subpx[2],
421 w,
422 h,
423 &mut |r| {
424 apply(data, style, transform, r);
425 },
426 fill,
427 pitch,
428 y_up,
429 &mut |row_offset, x, count, coverage| {
430 let buf = &mut buf[row_offset..];
431 let mut i = 0;
432 let mut j = x * 4 + 2;
433 while i < count {
434 buf[j] = coverage;
435 i += 1;
436 j += 4;
437 }
438 },
439 );
440 } else {
441 ras.rasterize(
442 shift,
443 w,
444 h,
445 &mut |r| {
446 apply(data, style, transform, r);
447 },
448 fill,
449 buf,
450 pitch,
451 y_up,
452 );
453 }
454 }
455}