1 | // Copyright 2019 the Resvg Authors |
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
3 | |
4 | use crate::render::Context; |
5 | |
6 | pub fn apply( |
7 | clip: &usvg::ClipPath, |
8 | transform: tiny_skia::Transform, |
9 | pixmap: &mut tiny_skia::Pixmap, |
10 | ) { |
11 | let mut clip_pixmap: Pixmap = tiny_skia::Pixmap::new(pixmap.width(), pixmap.height()).unwrap(); |
12 | clip_pixmap.fill(color:tiny_skia::Color::BLACK); |
13 | |
14 | draw_children( |
15 | parent:clip.root(), |
16 | mode:tiny_skia::BlendMode::Clear, |
17 | transform.pre_concat(clip.transform()), |
18 | &mut clip_pixmap.as_mut(), |
19 | ); |
20 | |
21 | if let Some(clip: &ClipPath) = clip.clip_path() { |
22 | apply(clip, transform, pixmap); |
23 | } |
24 | |
25 | let mut mask: Mask = tiny_skia::Mask::from_pixmap(clip_pixmap.as_ref(), tiny_skia::MaskType::Alpha); |
26 | mask.invert(); |
27 | pixmap.apply_mask(&mask); |
28 | } |
29 | |
30 | fn draw_children( |
31 | parent: &usvg::Group, |
32 | mode: tiny_skia::BlendMode, |
33 | transform: tiny_skia::Transform, |
34 | pixmap: &mut tiny_skia::PixmapMut, |
35 | ) { |
36 | for child in parent.children() { |
37 | match child { |
38 | usvg::Node::Path(ref path) => { |
39 | if !path.is_visible() { |
40 | continue; |
41 | } |
42 | |
43 | // We could use any values here. They will not be used anyway. |
44 | let ctx = Context { |
45 | max_bbox: tiny_skia::IntRect::from_xywh(0, 0, 1, 1).unwrap(), |
46 | }; |
47 | |
48 | crate::path::fill_path(path, mode, &ctx, transform, pixmap); |
49 | } |
50 | usvg::Node::Text(ref text) => { |
51 | draw_children(text.flattened(), mode, transform, pixmap); |
52 | } |
53 | usvg::Node::Group(ref group) => { |
54 | let transform = transform.pre_concat(group.transform()); |
55 | |
56 | if let Some(clip) = group.clip_path() { |
57 | // If a `clipPath` child also has a `clip-path` |
58 | // then we should render this child on a new canvas, |
59 | // clip it, and only then draw it to the `clipPath`. |
60 | clip_group(group, clip, transform, pixmap); |
61 | } else { |
62 | draw_children(group, mode, transform, pixmap); |
63 | } |
64 | } |
65 | _ => {} |
66 | } |
67 | } |
68 | } |
69 | |
70 | fn clip_group( |
71 | children: &usvg::Group, |
72 | clip: &usvg::ClipPath, |
73 | transform: tiny_skia::Transform, |
74 | pixmap: &mut tiny_skia::PixmapMut, |
75 | ) -> Option<()> { |
76 | let mut clip_pixmap: Pixmap = tiny_skia::Pixmap::new(pixmap.width(), pixmap.height()).unwrap(); |
77 | |
78 | draw_children( |
79 | parent:children, |
80 | mode:tiny_skia::BlendMode::SourceOver, |
81 | transform, |
82 | &mut clip_pixmap.as_mut(), |
83 | ); |
84 | apply(clip, transform, &mut clip_pixmap); |
85 | |
86 | let mut paint: PixmapPaint = tiny_skia::PixmapPaint::default(); |
87 | paint.blend_mode = tiny_skia::BlendMode::Xor; |
88 | pixmap.draw_pixmap( |
89 | x:0, |
90 | y:0, |
91 | clip_pixmap.as_ref(), |
92 | &paint, |
93 | tiny_skia::Transform::identity(), |
94 | mask:None, |
95 | ); |
96 | |
97 | Some(()) |
98 | } |
99 | |