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
5use crate::render::Context;
6
7pub 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
31fn 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
71fn 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