1// Copyright 2019 the Resvg Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use crate::render::Context;
5
6pub 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
30fn 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
70fn 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