summaryrefslogtreecommitdiff
path: root/usvg/src/convert/clippath.rs
blob: 46a736c6e85cc1b671b45eb16cd1a8d3048d2515 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// external
use svgdom;

// self
use tree;
use tree::NodeExt;
use super::prelude::*;
use super::{
    path,
    text,
    shapes,
    IriResolveResult,
};


pub fn convert(
    node: &svgdom::Node,
    tree: &mut tree::Tree,
) -> tree::Node {
    let attrs = node.attributes();

    let mut clip_path = None;
    if let Some(&AValue::FuncLink(ref link)) = attrs.get_type(AId::ClipPath) {
        if link.is_tag_name(EId::ClipPath) {
            clip_path = Some(link.id().to_string());
        }
    }

    tree.append_to_defs(
        tree::NodeKind::ClipPath(tree::ClipPath {
            id: node.id().clone(),
            units: super::convert_element_units(&attrs, AId::ClipPathUnits),
            transform: attrs.get_transform(AId::Transform).unwrap_or_default(),
            clip_path,
        })
    )
}

pub fn convert_children(
    parent_svg: &svgdom::Node,
    parent: &mut tree::Node,
    opt: &Options,
    tree: &mut tree::Tree,
) {
    for (id, node) in parent_svg.children().svg() {
        match id {
              EId::Rect
            | EId::Polyline
            | EId::Polygon
            | EId::Circle
            | EId::Ellipse => {
                if let Some(d) = shapes::convert(&node) {
                    path::convert(&node, d, opt, parent.clone(), tree);
                }
            }
            EId::Path => {
                let attrs = node.attributes();
                if let Some(d) = attrs.get_path(AId::D) {
                    path::convert(&node, d.clone(), opt, parent.clone(), tree);
                }
            }
            EId::Text => {
                text::convert(&node, opt, parent.clone(), tree);
            }
            EId::Line => {
                // `line` doesn't impact rendering because stroke is always disabled
                // for `clipPath` children. So we can ignore it completely.
            }
            EId::G => {
                // By the SVG spec, `clipPath` cannot contain a `g` element,
                // but since in `usvg` `clip-path` attribute can be set only for groups
                // we have to create one 'temporarily'.
                // It will be available in the tree, but will be ignored
                // during `Tree::to_svgdom` conversion.

                let attrs = node.attributes();
                let ts = attrs.get_transform(AId::Transform).unwrap_or_default();
                let opacity = attrs.get_number(AId::Opacity).map(|v| v.into());

                let clip_path = match super::resolve_iri(&node, EId::ClipPath, AId::ClipPath, tree) {
                    IriResolveResult::Id(id) => Some(id),
                    IriResolveResult::Skip => continue,
                    IriResolveResult::None => None,
                };

                let mask = match super::resolve_iri(&node, EId::Mask, AId::Mask, tree) {
                    IriResolveResult::Id(id) => Some(id),
                    IriResolveResult::Skip => continue,
                    IriResolveResult::None => None,
                };

                let filter = match super::resolve_iri(&node, EId::Filter, AId::Filter, tree) {
                    IriResolveResult::Id(id) => Some(id),
                    IriResolveResult::Skip => continue,
                    IriResolveResult::None => None,
                };

                if clip_path.is_none() && mask.is_none() && filter.is_none() {
                    continue;
                }

                let mut g_node = parent.append_kind(tree::NodeKind::Group(tree::Group {
                    id: node.id().clone(),
                    transform: ts,
                    opacity,
                    clip_path,
                    mask,
                    filter,
                }));

                convert_children(&node, &mut g_node, opt, tree);
            }
            _ => {
                warn!("Skipping the '{}' clipPath invalid child element '{}'.",
                      node.id(), id);
                continue;
            }
        }
    }
}