1use super::svgtree::{AId, SvgNode};
6use super::{converter, Options};
7use crate::{Group, Node};
8
9static FEATURES: &[&str] = &[
11 "http://www.w3.org/TR/SVG11/feature#SVGDOM-static",
12 "http://www.w3.org/TR/SVG11/feature#SVG-static",
13 "http://www.w3.org/TR/SVG11/feature#CoreAttribute", "http://www.w3.org/TR/SVG11/feature#Structure",
15 "http://www.w3.org/TR/SVG11/feature#BasicStructure",
16 "http://www.w3.org/TR/SVG11/feature#ContainerAttribute", "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
18 "http://www.w3.org/TR/SVG11/feature#Image",
19 "http://www.w3.org/TR/SVG11/feature#Style",
20 "http://www.w3.org/TR/SVG11/feature#Shape",
22 "http://www.w3.org/TR/SVG11/feature#Text",
23 "http://www.w3.org/TR/SVG11/feature#BasicText",
24 "http://www.w3.org/TR/SVG11/feature#PaintAttribute", "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute", "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
27 "http://www.w3.org/TR/SVG11/feature#GraphicsAttribute",
28 "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
29 "http://www.w3.org/TR/SVG11/feature#Marker",
30 "http://www.w3.org/TR/SVG11/feature#Gradient",
32 "http://www.w3.org/TR/SVG11/feature#Pattern",
33 "http://www.w3.org/TR/SVG11/feature#Clip",
34 "http://www.w3.org/TR/SVG11/feature#BasicClip",
35 "http://www.w3.org/TR/SVG11/feature#Mask",
36 "http://www.w3.org/TR/SVG11/feature#Filter",
37 "http://www.w3.org/TR/SVG11/feature#BasicFilter",
38 "http://www.w3.org/TR/SVG11/feature#XlinkAttribute",
40 ];
43
44pub(crate) fn convert(
45 node: SvgNode,
46 state: &converter::State,
47 cache: &mut converter::Cache,
48 parent: &mut Group,
49) -> Option<()> {
50 let child = node
51 .children()
52 .find(|n| is_condition_passed(*n, state.opt))?;
53 if let Some(g) = converter::convert_group(node, state, false, cache, parent, &|cache, g| {
54 converter::convert_element(child, state, cache, g);
55 }) {
56 parent.children.push(Node::Group(Box::new(g)));
57 }
58
59 Some(())
60}
61
62pub(crate) fn is_condition_passed(node: SvgNode, opt: &Options) -> bool {
63 if !node.is_element() {
64 return false;
65 }
66
67 if node.has_attribute(AId::RequiredExtensions) {
68 return false;
69 }
70
71 if let Some(features) = node.attribute::<&str>(AId::RequiredFeatures) {
77 for feature in features.split(' ') {
78 if !FEATURES.contains(&feature) {
79 return false;
80 }
81 }
82 }
83
84 if !is_valid_sys_lang(node, opt) {
85 return false;
86 }
87
88 true
89}
90
91fn is_valid_sys_lang(node: SvgNode, opt: &Options) -> bool {
93 if let Some(langs) = node.attribute::<&str>(AId::SystemLanguage) {
99 let mut has_match = false;
100 for lang in langs.split(',') {
101 let lang = lang.trim();
102
103 if opt.languages.iter().any(|v| v == lang) {
106 has_match = true;
107 break;
108 }
109
110 if let Some(idx) = lang.bytes().position(|c| c == b'-') {
114 let lang_prefix = &lang[..idx];
115 if opt.languages.iter().any(|v| v == lang_prefix) {
116 has_match = true;
117 break;
118 }
119 }
120 }
121
122 has_match
123 } else {
124 true
125 }
126}