1use crate::{cache, render::Context, PixmapPool, SvgrCache};
6use tiny_skia::IntSize;
7
8pub fn apply(
9 clip: &usvgr::ClipPath,
10 transform: tiny_skia::Transform,
11 pixmap: &mut tiny_skia::Pixmap,
12 cache: &mut cache::SvgrCache,
13 pixmap_pool: &cache::PixmapPool,
14) {
15 let clip_pixmap = cache
16 .with_subpixmap_cache(
17 clip,
18 transform,
19 pixmap_pool,
20 IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap(),
21 |mut clip_pixmap, cache| {
22 clip_pixmap.fill(tiny_skia::Color::BLACK);
23
24 draw_children(
25 clip.root(),
26 tiny_skia::BlendMode::Clear,
27 transform.pre_concat(clip.transform()),
28 &mut clip_pixmap.as_mut(),
29 cache,
30 &PixmapPool::new(),
31 );
32
33 Some(clip_pixmap)
34 },
35 )
36 .expect("failed to allocate pixmap for clip");
37
38 if let Some(clip) = clip.clip_path() {
39 apply(
42 clip,
43 transform,
44 pixmap,
45 &mut SvgrCache::none(),
46 &PixmapPool::new(),
47 );
48 }
49
50 let mut mask = tiny_skia::Mask::from_pixmap(clip_pixmap.as_ref(), tiny_skia::MaskType::Alpha);
51 mask.invert();
52 pixmap.apply_mask(&mask);
53}
54
55fn draw_children(
56 parent: &usvgr::Group,
57 mode: tiny_skia::BlendMode,
58 transform: tiny_skia::Transform,
59 pixmap: &mut tiny_skia::PixmapMut,
60 cache: &mut cache::SvgrCache,
61 pixmap_pool: &cache::PixmapPool,
62) {
63 for child in parent.children() {
64 match child {
65 usvgr::Node::Path(ref path) => {
66 if path.visibility() != usvgr::Visibility::Visible {
67 continue;
68 }
69
70 let ctx = Context {
71 max_bbox: tiny_skia::IntRect::from_xywh(0, 0, 1, 1).unwrap(),
73 };
74
75 crate::path::fill_path(path, mode, &ctx, transform, pixmap, cache, pixmap_pool);
76 }
77 usvgr::Node::Text(ref text) => {
78 draw_children(
79 text.flattened(),
80 mode,
81 transform,
82 pixmap,
83 cache,
84 pixmap_pool,
85 );
86 }
87 usvgr::Node::Group(ref group) => {
88 let transform = transform.pre_concat(group.transform());
89
90 if let Some(clip) = group.clip_path() {
91 clip_group(group, clip, transform, pixmap, cache, pixmap_pool);
95 } else {
96 draw_children(group, mode, transform, pixmap, cache, pixmap_pool);
97 }
98 }
99 _ => {}
100 }
101 }
102}
103
104fn clip_group(
105 children: &usvgr::Group,
106 clip: &usvgr::ClipPath,
107 transform: tiny_skia::Transform,
108 pixmap: &mut tiny_skia::PixmapMut,
109 cache: &mut cache::SvgrCache,
110 pixmap_pool: &cache::PixmapPool,
111) -> Option<()> {
112 let mut clip_pixmap = pixmap_pool
113 .take_or_allocate(pixmap.width(), pixmap.height())
114 .unwrap();
115
116 draw_children(
117 children,
118 tiny_skia::BlendMode::SourceOver,
119 transform,
120 &mut clip_pixmap.as_mut(),
121 cache,
122 pixmap_pool,
123 );
124 apply(clip, transform, &mut clip_pixmap, cache, pixmap_pool);
125
126 let mut paint = tiny_skia::PixmapPaint::default();
127 paint.blend_mode = tiny_skia::BlendMode::Xor;
128 pixmap.draw_pixmap(
129 0,
130 0,
131 clip_pixmap.as_ref(),
132 &paint,
133 tiny_skia::Transform::identity(),
134 None,
135 );
136
137 Some(())
138}