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