1use pax_runtime_api::{Fill, Stroke, StrokeCap, StrokeJoin};
2use piet::{
3 kurbo::{self, Affine, Shape},
4 InterpolationMode, LineCap, LineJoin, LinearGradient, RadialGradient, StrokeStyle,
5};
6use std::{
7 cell::RefCell,
8 collections::{HashMap, HashSet},
9 rc::Rc,
10};
11
12use super::layer_surface::{
13 replay_batches_by_directional_priority, surface_intersects_coverage_bounds, LayerSurfaceEntry,
14 LayerSurfaceLayout, LayoutChangeKind, ReplayPriorityEntry, SurfaceReplayCoordinator,
15};
16#[cfg(debug_assertions)]
17use super::layer_surface::{visible_surface_escape, VisibleSurfaceEscape};
18use crate::api;
19
20#[cfg(debug_assertions)]
21fn log_visible_surface_escape(layer: usize, escape: VisibleSurfaceEscape) {
22 log::warn!(
23 "[pax-tile-window-escape] backend=piet layer={} visible_surfaces={} escaped_visible_surfaces={} max_gap_x={:.1} max_gap_y={:.1} previous_bounds={} visible_bounds={}",
24 layer,
25 escape.visible_surfaces,
26 escape.escaped_visible_surfaces,
27 escape.max_gap_x,
28 escape.max_gap_y,
29 format_rect(escape.previous_bounds),
30 format_rect(escape.visible_bounds),
31 );
32}
33
34#[cfg(debug_assertions)]
35fn format_rect(bounds: kurbo::Rect) -> String {
36 format!(
37 "{:.1},{:.1}-{:.1},{:.1}",
38 bounds.x0, bounds.y0, bounds.x1, bounds.y1
39 )
40}
41
42struct ImgData<R: piet::RenderContext> {
43 img: R::Image,
44 size: (usize, usize),
45}
46
47type ClearFn = Box<dyn Fn()>;
48type ConfigureFn = Box<dyn Fn(f32, f32, u32, u32, [f32; 2], bool)>;
49type LayerDef<R> = (PietLayerTarget<R>, Box<dyn Fn() -> LayerSurfaceLayout>);
50
51pub struct PietLayerRenderer<R: piet::RenderContext> {
53 key: String,
54 host_signature: String,
55 context: R,
56 clear_fn: ClearFn,
57 configure_fn: ConfigureFn,
58 origin_x: f32,
59 origin_y: f32,
60 logical_width: f32,
61 logical_height: f32,
62 surface_width: u32,
63 surface_height: u32,
64 dpr: [f32; 2],
65}
66
67impl<R: piet::RenderContext> PietLayerRenderer<R> {
68 pub fn new(
69 key: String,
70 host_signature: String,
71 context: R,
72 clear_fn: ClearFn,
73 configure_fn: ConfigureFn,
74 surface: &LayerSurfaceEntry,
75 ) -> Self {
76 Self {
77 key,
78 host_signature,
79 context,
80 clear_fn,
81 configure_fn,
82 origin_x: surface.origin_x,
83 origin_y: surface.origin_y,
84 logical_width: surface.surface.logical_width,
85 logical_height: surface.surface.logical_height,
86 surface_width: surface.surface.surface_width,
87 surface_height: surface.surface.surface_height,
88 dpr: surface.surface.dpr,
89 }
90 }
91
92 fn context_mut(&mut self) -> &mut R {
93 &mut self.context
94 }
95
96 fn clear(&self) {
97 (self.clear_fn)();
98 }
99
100 fn intersects_coverage_bounds(&self, bounds: &kurbo::Rect) -> bool {
101 surface_intersects_coverage_bounds(
102 bounds,
103 self.origin_x as f64,
104 self.origin_y as f64,
105 self.logical_width as f64,
106 self.logical_height as f64,
107 )
108 }
109
110 fn coverage_bounds(&self) -> kurbo::Rect {
111 kurbo::Rect::new(
112 self.origin_x as f64,
113 self.origin_y as f64,
114 self.origin_x as f64 + self.logical_width as f64,
115 self.origin_y as f64 + self.logical_height as f64,
116 )
117 }
118
119 fn update_layout(&mut self, surface: &LayerSurfaceEntry) -> LayoutChangeKind {
120 let origin_changed = (self.origin_x - surface.origin_x).abs() > f32::EPSILON
121 || (self.origin_y - surface.origin_y).abs() > f32::EPSILON;
122 let size_changed = self.logical_width != surface.surface.logical_width
123 || self.logical_height != surface.surface.logical_height
124 || self.surface_width != surface.surface.surface_width
125 || self.surface_height != surface.surface.surface_height
126 || self.dpr != surface.surface.dpr;
127
128 self.origin_x = surface.origin_x;
129 self.origin_y = surface.origin_y;
130 self.logical_width = surface.surface.logical_width;
131 self.logical_height = surface.surface.logical_height;
132 self.surface_width = surface.surface.surface_width;
133 self.surface_height = surface.surface.surface_height;
134 self.dpr = surface.surface.dpr;
135
136 if size_changed || origin_changed {
137 (self.configure_fn)(
138 self.origin_x,
139 self.origin_y,
140 self.surface_width,
141 self.surface_height,
142 self.dpr,
143 size_changed,
144 );
145 }
146
147 if size_changed {
148 self.clear();
149 }
150
151 if size_changed {
152 LayoutChangeKind::Resized
153 } else if origin_changed {
154 LayoutChangeKind::OriginOnly
155 } else {
156 LayoutChangeKind::Unchanged
157 }
158 }
159}
160
161pub struct PietLayerTarget<R: piet::RenderContext> {
163 renderers: Vec<PietLayerRenderer<R>>,
164 active: bool,
165}
166
167impl<R: piet::RenderContext> PietLayerTarget<R> {
168 pub fn new(renderers: Vec<PietLayerRenderer<R>>, active: bool) -> Self {
169 Self { renderers, active }
170 }
171
172 fn activate(&mut self) -> bool {
173 let changed = !self.active;
174 self.active = true;
175 changed
176 }
177
178 fn deactivate(&mut self) {
179 self.active = false;
180 }
181}
182
183pub struct PietRenderer<R: piet::RenderContext> {
185 layers: Vec<LayerDef<R>>,
186 image_map: HashMap<String, ImgData<R>>,
187 layer_factory: Box<dyn Fn(usize) -> LayerDef<R>>,
188 ready_layers: Vec<usize>,
189 replay_layers: Vec<usize>,
190 surface_replay: SurfaceReplayCoordinator,
191 active_render_scopes: Vec<Vec<Vec<usize>>>,
192 clean_skipped_canvas_nodes: HashSet<(usize, u32)>,
193}
194
195impl<R: piet::RenderContext> PietRenderer<R> {
196 pub fn new(layer_factory: impl Fn(usize) -> LayerDef<R> + 'static) -> Self {
198 Self {
199 layer_factory: Box::new(layer_factory),
200 layers: Vec::new(),
201 image_map: HashMap::new(),
202 ready_layers: Vec::new(),
203 replay_layers: Vec::new(),
204 surface_replay: SurfaceReplayCoordinator::default(),
205 active_render_scopes: Vec::new(),
206 clean_skipped_canvas_nodes: HashSet::new(),
207 }
208 }
209
210 fn first_context_mut(&mut self) -> Option<&mut R> {
211 self.layers
212 .iter_mut()
213 .find_map(|(target, _)| target.renderers.first_mut())
214 .map(PietLayerRenderer::context_mut)
215 }
216
217 fn with_layer_context(&mut self, layer: usize, mut f: impl FnMut(&mut R)) {
218 let scoped_indices = self
219 .active_render_scopes
220 .get(layer)
221 .and_then(|scopes| scopes.last())
222 .cloned();
223
224 let Some((target, _)) = self.layers.get_mut(layer) else {
225 return;
226 };
227 if !target.active {
228 return;
229 }
230
231 if let Some(indices) = scoped_indices {
232 for index in indices {
233 if let Some(renderer) = target.renderers.get_mut(index) {
234 f(renderer.context_mut());
235 }
236 }
237 } else {
238 for renderer in &mut target.renderers {
239 f(renderer.context_mut());
240 }
241 }
242 }
243
244 fn push_render_scope(&mut self, layer: usize, renderer_indices: Vec<usize>) {
245 if self.active_render_scopes.len() <= layer {
246 self.active_render_scopes.resize_with(layer + 1, Vec::new);
247 }
248 self.active_render_scopes[layer].push(renderer_indices);
249 }
250
251 fn pop_render_scope(&mut self, layer: usize) {
252 if let Some(scopes) = self.active_render_scopes.get_mut(layer) {
253 scopes.pop();
254 }
255 }
256
257 fn take_replay_layer_ids(&mut self) -> Vec<usize> {
258 let mut replay = std::mem::take(&mut self.replay_layers);
259 replay.sort_unstable();
260 replay.dedup();
261 replay
262 }
263
264 fn targeted_or_all_indices(&self, layer: usize, renderer_count: usize) -> Vec<usize> {
265 self.surface_replay
266 .targeted_or_all_indices(layer, renderer_count)
267 }
268
269 fn clear_targeted_replay_scope(&mut self, layer: usize) {
270 self.surface_replay.clear_targeted_replay_scope(layer);
271 }
272
273 fn set_targeted_replay_batches(
274 &mut self,
275 layer: usize,
276 batches: Vec<Vec<usize>>,
277 bounds_by_surface: HashMap<usize, Vec<kurbo::Rect>>,
278 ) {
279 self.surface_replay
280 .set_targeted_replay_batches(layer, batches, bounds_by_surface);
281 }
282
283 fn advance_targeted_replay_queue(&mut self, layer: usize) -> bool {
284 self.surface_replay.advance_targeted_replay_queue(layer)
285 }
286
287 fn remember_canvas_node_coverage(
288 &mut self,
289 layer: usize,
290 node_id: u32,
291 coverage_bounds: kurbo::Rect,
292 ) {
293 self.surface_replay
294 .remember_canvas_node_coverage(layer, node_id, coverage_bounds);
295 }
296
297 fn forget_canvas_node_coverage(&mut self, layer: usize, node_id: u32) {
298 self.surface_replay
299 .forget_canvas_node_coverage(layer, node_id);
300 }
301
302 fn targeted_replay_surface_bounds(
303 &self,
304 layer: usize,
305 target: &PietLayerTarget<R>,
306 ) -> Option<Vec<kurbo::Rect>> {
307 self.surface_replay
308 .targeted_replay_surface_bounds(layer, |index| {
309 target
310 .renderers
311 .get(index)
312 .map(PietLayerRenderer::coverage_bounds)
313 })
314 }
315
316 fn spatial_replay_node_ids(&self, layer: usize) -> Option<Vec<u32>> {
317 let Some((target, _)) = self.layers.get(layer) else {
318 return None;
319 };
320 let surface_bounds = self.targeted_replay_surface_bounds(layer, target)?;
321 self.surface_replay
322 .spatial_replay_node_ids_for_surface_bounds(layer, &surface_bounds)
323 }
324
325 fn refresh_layer_layouts<I>(&mut self, layer_indices: I)
326 where
327 I: IntoIterator<Item = usize>,
328 {
329 for layer_index in layer_indices {
330 let Some((target, layout_provider)) = self.layers.get_mut(layer_index) else {
331 continue;
332 };
333 let layout = (layout_provider)();
334 let layout_matches = layer_layout_matches_target(target, &layout);
335
336 if !layout.active {
337 target.deactivate();
338 self.clear_targeted_replay_scope(layer_index);
339 continue;
340 }
341
342 if !layout_matches {
343 self.clear_targeted_replay_scope(layer_index);
344 let (new_target, new_provider) = (self.layer_factory)(layer_index);
345 let has_surfaces = !new_target.renderers.is_empty();
346 self.layers[layer_index] = (new_target, new_provider);
347 if has_surfaces {
348 self.ready_layers.push(layer_index);
349 self.replay_layers.push(layer_index);
350 }
351 continue;
352 }
353
354 let activated_replay = target.activate() && !target.renderers.is_empty();
355
356 let mut targeted_replay_entries = Vec::new();
357 let mut targeted_replay_bounds = HashMap::new();
358 let mut needs_full_layer_replay = false;
359 #[cfg(debug_assertions)]
360 {
361 let previous_surface_bounds: Vec<_> = target
362 .renderers
363 .iter()
364 .map(PietLayerRenderer::coverage_bounds)
365 .collect();
366 if let Some(escape) =
367 visible_surface_escape(&previous_surface_bounds, &layout.surfaces)
368 {
369 log_visible_surface_escape(layer_index, escape);
370 }
371 }
372 for (index, (surface, renderer)) in layout
373 .surfaces
374 .iter()
375 .zip(target.renderers.iter_mut())
376 .enumerate()
377 {
378 let previous_bounds = renderer.coverage_bounds();
379 let layout_change = renderer.update_layout(surface);
380 let current_bounds = renderer.coverage_bounds();
381 match layout_change {
382 LayoutChangeKind::Unchanged => {}
383 LayoutChangeKind::OriginOnly => {
384 targeted_replay_entries.push(ReplayPriorityEntry::new(
385 index,
386 surface.replay_priority,
387 previous_bounds,
388 current_bounds,
389 ));
390 targeted_replay_bounds.insert(index, vec![previous_bounds, current_bounds]);
391 }
392 LayoutChangeKind::Resized => {
393 needs_full_layer_replay = true;
394 }
395 }
396 }
397 if activated_replay || needs_full_layer_replay {
398 self.clear_targeted_replay_scope(layer_index);
399 self.replay_layers.push(layer_index);
400 } else if !targeted_replay_entries.is_empty() {
401 self.set_targeted_replay_batches(
402 layer_index,
403 piet_replay_batches_for_retarget(targeted_replay_entries),
404 targeted_replay_bounds,
405 );
406 self.replay_layers.push(layer_index);
407 }
408 }
409 }
410}
411
412fn piet_replay_batches_for_retarget(entries: Vec<ReplayPriorityEntry>) -> Vec<Vec<usize>> {
413 let batches = replay_batches_by_directional_priority(&entries);
414 let visible_indices: HashSet<_> = entries
415 .iter()
416 .filter(|entry| entry.priority <= 0)
417 .map(|entry| entry.index)
418 .collect();
419 if visible_indices.is_empty() {
420 return batches;
421 }
422
423 let mut visible_batch = Vec::new();
424 let mut warm_batches = Vec::new();
425 for batch in batches {
426 let mut warm_batch = Vec::new();
427 for index in batch {
428 if visible_indices.contains(&index) {
429 visible_batch.push(index);
430 } else {
431 warm_batch.push(index);
432 }
433 }
434 if !warm_batch.is_empty() {
435 warm_batches.push(warm_batch);
436 }
437 }
438
439 let mut coalesced_batches = Vec::with_capacity(warm_batches.len() + 1);
440 coalesced_batches.push(visible_batch);
441 coalesced_batches.extend(warm_batches);
442 coalesced_batches
443}
444
445fn layer_layout_matches_target<R: piet::RenderContext>(
446 target: &PietLayerTarget<R>,
447 layout: &LayerSurfaceLayout,
448) -> bool {
449 layout.surfaces.len() == target.renderers.len()
450 && layout
451 .surfaces
452 .iter()
453 .zip(target.renderers.iter())
454 .all(|(surface, renderer)| {
455 surface.key == renderer.key && surface.host_signature == renderer.host_signature
456 })
457}
458
459#[cfg(test)]
460mod tests {
461 use super::piet_replay_batches_for_retarget;
462 use crate::engine::layer_surface::ReplayPriorityEntry;
463 use kurbo::Rect;
464
465 #[test]
466 fn piet_replay_batches_coalesce_visible_surfaces_first() {
467 let batches = piet_replay_batches_for_retarget(vec![
468 replay_entry(0, 0, 0.0, 100.0),
469 replay_entry(1, 0, 100.0, 200.0),
470 replay_entry(2, 1, 200.0, 300.0),
471 replay_entry(3, 1, -100.0, 0.0),
472 ]);
473
474 assert_eq!(batches[0], vec![1, 0]);
475 assert_eq!(batches[1], vec![2]);
476 assert_eq!(batches[2], vec![3]);
477 }
478
479 #[test]
480 fn piet_replay_batches_keep_warm_only_directional_batches() {
481 let batches = piet_replay_batches_for_retarget(vec![
482 replay_entry(0, 1, 0.0, 100.0),
483 replay_entry(1, 1, 100.0, 200.0),
484 replay_entry(2, 1, -100.0, 0.0),
485 ]);
486
487 assert_eq!(batches, vec![vec![1], vec![0], vec![2]]);
488 }
489
490 fn replay_entry(
491 index: usize,
492 priority: i32,
493 previous_y: f64,
494 current_y: f64,
495 ) -> ReplayPriorityEntry {
496 ReplayPriorityEntry::new(
497 index,
498 priority,
499 Rect::new(0.0, previous_y, 100.0, previous_y + 100.0),
500 Rect::new(0.0, current_y, 100.0, current_y + 100.0),
501 )
502 }
503}
504
505impl<R: piet::RenderContext> api::RenderContext for PietRenderer<R> {
506 fn fill_with_opacity(&mut self, layer: usize, path: kurbo::BezPath, fill: &Fill, opacity: f64) {
507 let rect = path.bounding_box();
508 let brush = fill_to_piet_brush(&fill.with_alpha_factor(opacity), rect);
509 self.with_layer_context(layer, |context| context.fill(path.clone(), &brush));
510 }
511
512 fn stroke_with_opacity(
513 &mut self,
514 layer: usize,
515 path: kurbo::BezPath,
516 stroke: &Stroke,
517 opacity: f64,
518 ) {
519 let rect = path.bounding_box();
520 let brush = fill_to_piet_brush(
521 &Fill::Solid(stroke.color.get()).with_alpha_factor(opacity),
522 rect,
523 );
524 let width = stroke.width.get().expect_pixels().to_float();
525 let style = stroke_to_piet_style(stroke);
526 self.with_layer_context(layer, |context| {
527 context.stroke_styled(path.clone(), &brush, width, &style)
528 });
529 }
530
531 fn stroke_with_draw_range_and_material_and_opacity(
532 &mut self,
533 layer: usize,
534 path: kurbo::BezPath,
535 stroke: &Stroke,
536 _material: &api::Material,
537 opacity: f64,
538 draw_start: f64,
539 draw_end: f64,
540 ) {
541 let draw_start = draw_start.clamp(0.0, 1.0);
542 let draw_end = draw_end.clamp(0.0, 1.0);
543 if draw_start >= draw_end {
544 return;
545 }
546 let path = if draw_start <= f64::EPSILON && draw_end >= 1.0 - f64::EPSILON {
547 path
548 } else {
549 api::drawing::path_trim::trim_bez_path(&path, draw_start, draw_end)
550 };
551 self.stroke_with_opacity(layer, path, stroke, opacity);
552 }
553
554 fn save(&mut self, layer: usize) {
555 self.with_layer_context(layer, |context| {
556 let _ = context.save();
557 });
558 }
559
560 fn transform(&mut self, layer: usize, affine: Affine) {
561 self.with_layer_context(layer, |context| context.transform(affine));
562 }
563
564 fn clip(&mut self, layer: usize, path: kurbo::BezPath) {
565 self.with_layer_context(layer, |context| context.clip(path.clone()));
566 }
567
568 fn restore(&mut self, layer: usize) {
569 self.with_layer_context(layer, |context| {
570 let _ = context.restore();
571 });
572 }
573
574 fn load_image(&mut self, path: &str, buf: &[u8], width: usize, height: usize) {
575 let Some(render_context) = self.first_context_mut() else {
576 return;
577 };
578 let img = render_context
579 .make_image(width, height, buf, piet::ImageFormat::RgbaSeparate)
580 .expect("image creation successful");
581 self.image_map.insert(
582 path.to_owned(),
583 ImgData {
584 img,
585 size: (width, height),
586 },
587 );
588 }
589
590 fn get_image_size(&mut self, image_path: &str) -> Option<(usize, usize)> {
591 self.image_map.get(image_path).map(|img| img.size)
592 }
593
594 fn draw_image(&mut self, layer: usize, image_path: &str, rect: kurbo::Rect) {
595 let Some(data) = self.image_map.get(image_path) else {
596 return;
597 };
598 let scoped_indices = self
599 .active_render_scopes
600 .get(layer)
601 .and_then(|scopes| scopes.last())
602 .cloned();
603 let Some((target, _)) = self.layers.get_mut(layer) else {
604 return;
605 };
606 if !target.active {
607 return;
608 }
609 if let Some(indices) = scoped_indices {
610 for index in indices {
611 if let Some(renderer) = target.renderers.get_mut(index) {
612 renderer
613 .context_mut()
614 .draw_image(&data.img, rect, InterpolationMode::Bilinear);
615 }
616 }
617 } else {
618 for renderer in &mut target.renderers {
619 renderer
620 .context_mut()
621 .draw_image(&data.img, rect, InterpolationMode::Bilinear);
622 }
623 }
624 }
625
626 fn layers(&self) -> usize {
627 self.layers.len()
628 }
629
630 fn resize_layers_to(&mut self, layer_count: usize, dirty_canvases: Rc<RefCell<Vec<bool>>>) {
631 let current_len = self.layers.len();
632 match layer_count.cmp(¤t_len) {
633 std::cmp::Ordering::Less => {
634 self.layers.truncate(layer_count);
635 self.active_render_scopes.truncate(layer_count);
636 self.surface_replay.truncate_layers(layer_count);
637 }
638 std::cmp::Ordering::Equal => return,
639 std::cmp::Ordering::Greater => {
640 for i in current_len..layer_count {
641 let (target, provider) = (self.layer_factory)(i);
642 let has_surfaces = target.active && !target.renderers.is_empty();
643 self.layers.push((target, provider));
644 if let Some(dirty_bit) = dirty_canvases.borrow_mut().get_mut(i) {
645 *dirty_bit = true;
646 }
647 if has_surfaces {
648 self.ready_layers.push(i);
649 }
650 }
651 }
652 }
653 }
654
655 fn image_loaded(&self, path: &str) -> bool {
656 self.image_map.contains_key(path)
657 }
658
659 fn clear(&mut self, layer: usize) {
660 let scoped_indices = self
661 .active_render_scopes
662 .get(layer)
663 .and_then(|scopes| scopes.last())
664 .cloned()
665 .or_else(|| {
666 self.layers
667 .get(layer)
668 .map(|(target, _)| self.targeted_or_all_indices(layer, target.renderers.len()))
669 });
670 let Some((target, _)) = self.layers.get_mut(layer) else {
671 return;
672 };
673 if !target.active {
674 return;
675 }
676 if let Some(indices) = scoped_indices {
677 for index in indices {
678 if let Some(renderer) = target.renderers.get(index) {
679 renderer.clear();
680 }
681 }
682 } else {
683 for renderer in &target.renderers {
684 renderer.clear();
685 }
686 }
687 }
688
689 fn flush(&mut self, layer: usize, _dirty_canvases: Rc<RefCell<Vec<bool>>>) {
690 if self.advance_targeted_replay_queue(layer) {
691 self.replay_layers.push(layer);
692 }
693 }
694
695 fn resize(&mut self, _width: usize, _height: usize) {
696 let layer_count = self.layers.len();
697 self.refresh_layer_layouts(0..layer_count);
698 }
699
700 fn refresh_layers(&mut self, layers: &[usize]) {
701 self.refresh_layer_layouts(layers.iter().copied());
702 }
703
704 fn clear_targeted_replay(&mut self, layer: usize) {
705 self.clear_targeted_replay_scope(layer);
706 }
707
708 fn take_ready_canvas_layers(&mut self) -> Vec<usize> {
709 let mut ready = std::mem::take(&mut self.ready_layers);
710 ready.sort_unstable();
711 ready.dedup();
712 ready
713 }
714
715 fn take_replay_canvas_layer_updates(
716 &mut self,
717 ) -> Vec<pax_runtime_api::ReplayCanvasLayerUpdate> {
718 let replay_layers = self.take_replay_layer_ids();
719 replay_layers
720 .into_iter()
721 .map(|layer| pax_runtime_api::ReplayCanvasLayerUpdate {
722 layer,
723 node_ids: self.spatial_replay_node_ids(layer),
724 })
725 .collect()
726 }
727
728 fn retains_canvas_nodes(&self) -> bool {
729 false
730 }
731
732 fn begin_node(&mut self, layer: usize, _node_id: u32, _z_index: i32, _light_mask: u32) -> bool {
733 let renderer_count = {
734 let Some((target, _)) = self.layers.get(layer) else {
735 return false;
736 };
737 if !target.active {
738 return false;
739 }
740 target.renderers.len()
741 };
742 self.remember_canvas_node_coverage(
743 layer,
744 _node_id,
745 kurbo::Rect::new(
746 f64::NEG_INFINITY,
747 f64::NEG_INFINITY,
748 f64::INFINITY,
749 f64::INFINITY,
750 ),
751 );
752 let selected = self.targeted_or_all_indices(layer, renderer_count);
753 let began = !selected.is_empty();
754 if began {
755 self.push_render_scope(layer, selected);
756 }
757 began
758 }
759
760 fn begin_node_with_bounds(
761 &mut self,
762 layer: usize,
763 node_id: u32,
764 _z_index: i32,
765 coverage_bounds: kurbo::Rect,
766 _light_mask: u32,
767 ) -> bool {
768 let renderer_count = {
769 let Some((target, _)) = self.layers.get(layer) else {
770 return false;
771 };
772 if !target.active {
773 return false;
774 }
775 target.renderers.len()
776 };
777 self.remember_canvas_node_coverage(layer, node_id, coverage_bounds);
778 let candidate_indices = self.targeted_or_all_indices(layer, renderer_count);
779 let Some((target, _)) = self.layers.get(layer) else {
780 return false;
781 };
782 let selected: Vec<_> = target
783 .renderers
784 .iter()
785 .enumerate()
786 .filter(|(index, _)| candidate_indices.contains(index))
787 .filter_map(|(index, renderer)| {
788 renderer
789 .intersects_coverage_bounds(&coverage_bounds)
790 .then_some(index)
791 })
792 .collect();
793 let began = !selected.is_empty();
794 if began {
795 self.push_render_scope(layer, selected);
796 } else {
797 self.clean_skipped_canvas_nodes.insert((layer, node_id));
798 }
799 began
800 }
801
802 fn take_clean_skipped_node(&mut self, layer: usize, node_id: u32) -> bool {
803 self.clean_skipped_canvas_nodes.remove(&(layer, node_id))
804 }
805
806 fn end_node(&mut self, layer: usize, _node_id: u32) -> bool {
807 self.pop_render_scope(layer);
808 true
809 }
810
811 fn remove_node(&mut self, layer: usize, node_id: u32) -> bool {
812 self.forget_canvas_node_coverage(layer, node_id);
813 true
814 }
815}
816
817fn fill_to_piet_brush(fill: &Fill, rect: kurbo::Rect) -> piet::PaintBrush {
818 match fill {
819 Fill::Solid(color) => color.to_piet_color().into(),
820 Fill::LinearGradient(linear) => {
821 let linear_gradient = LinearGradient::new(
822 Fill::to_unit_point(linear.start, (rect.width(), rect.height())),
823 Fill::to_unit_point(linear.end, (rect.width(), rect.height())),
824 Fill::to_piet_gradient_stops(linear.stops.clone()),
825 );
826 linear_gradient.into()
827 }
828 Fill::RadialGradient(radial) => {
829 let origin = Fill::to_unit_point(radial.start, (rect.width(), rect.height()));
830 let center = Fill::to_unit_point(radial.end, (rect.width(), rect.height()));
831 let gradient_stops = Fill::to_piet_gradient_stops(radial.stops.clone());
832 let radial_gradient = RadialGradient::new(radial.radius, gradient_stops)
833 .with_center(center)
834 .with_origin(origin);
835 radial_gradient.into()
836 }
837 }
838}
839
840fn stroke_to_piet_style(stroke: &Stroke) -> StrokeStyle {
841 let mut style = StrokeStyle::new();
842 style.set_line_cap(match stroke.cap.get() {
843 StrokeCap::Butt => LineCap::Butt,
844 StrokeCap::Round => LineCap::Round,
845 StrokeCap::Square => LineCap::Square,
846 });
847 style.set_line_join(match stroke.join.get() {
848 StrokeJoin::Miter => LineJoin::Miter { limit: 4.0 },
849 StrokeJoin::Round => LineJoin::Round,
850 StrokeJoin::Bevel => LineJoin::Bevel,
851 });
852 style
853}