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