use svgdom::{
Length,
Transform,
};
use super::prelude::*;
pub fn prepare_use(doc: &Document) {
for mut node in doc.root().descendants().filter(|n| n.is_tag_name(EId::Use)) {
node.set_attribute_if_none((AId::X, 0.0));
node.set_attribute_if_none((AId::Y, 0.0));
node.set_attribute_if_none((AId::Width, Length::new(100.0, Unit::Percent)));
node.set_attribute_if_none((AId::Height, Length::new(100.0, Unit::Percent)));
}
}
pub fn resolve_use(doc: &mut Document) {
let mut rm_nodes = Vec::new();
let mut is_any_resolved = true;
while is_any_resolved {
is_any_resolved = false;
rm_nodes.clear();
for mut node in doc.root().descendants().filter(|n| n.is_tag_name(EId::Use)) {
let av = node.attributes().get_value(("xlink", AId::Href)).cloned();
if let Some(AValue::Link(mut link)) = av {
if link.is_tag_name(EId::Use) {
continue;
}
if link.is_tag_name(EId::Svg) {
warn!("'use' element linked to an 'svg' element is not supported. Skipped.");
rm_nodes.push(node.clone());
continue;
}
let mut is_recursive = false;
for link_child in link.descendants().skip(1).filter(|n| n.is_tag_name(EId::Use)) {
let av = link_child.attributes().get_value(("xlink", AId::Href)).cloned();
if let Some(AValue::Link(link2)) = av {
if link2 == node {
is_recursive = true;
break;
}
}
}
if is_recursive {
warn!("Recursive 'use' detected. '{}' will be deleted.", node.id());
rm_nodes.push(node.clone());
continue;
}
_resolve_use(doc, &mut node, &mut link);
is_any_resolved = true;
}
}
for node in &mut rm_nodes {
doc.remove_node(node.clone());
}
}
}
fn _resolve_use(
doc: &mut Document,
use_node: &mut Node,
linked_node: &mut Node,
) {
use_node.remove_attribute(("xlink", AId::Href));
use_node.set_tag_name(EId::G);
use_node.set_attribute(("usvg-group", 1));
let orig_ts = use_node.attributes().get_transform(AId::Transform).unwrap_or_default();
use_node.remove_attribute(AId::Transform);
{
let x = use_node.attributes().get_number_or(AId::X, 0.0);
let y = use_node.attributes().get_number_or(AId::Y, 0.0);
if !(x.is_fuzzy_zero() && y.is_fuzzy_zero()) {
use_node.append_transform(Transform::new_translate(x, y));
}
}
if linked_node.is_tag_name(EId::Symbol) {
resolve_symbol(doc, use_node, linked_node, orig_ts)
} else {
let new_node = doc.copy_node_deep(linked_node.clone());
use_node.append(new_node);
use_node.prepend_transform(orig_ts);
}
use_node.remove_attribute(AId::X);
use_node.remove_attribute(AId::Y);
use_node.remove_attribute(AId::Width);
use_node.remove_attribute(AId::Height);
for mut node in use_node.descendants().skip(1) {
if node.has_attribute("resolved-font-size") {
let parent = node.parent().unwrap_or(use_node.clone());
let fs = parent.find_attribute(AId::FontSize).unwrap_or(DEFAULT_FONT_SIZE);
node.set_attribute((AId::FontSize, fs));
}
}
}
fn resolve_symbol(
doc: &mut Document,
use_node: &mut Node,
linked_node: &mut Node,
orig_ts: Transform,
) {
linked_node.copy_attribute_to(AId::Overflow, use_node);
if linked_node.has_attribute(AId::ViewBox) {
use_node.copy_attribute_to(AId::Width, linked_node);
use_node.copy_attribute_to(AId::Height, linked_node);
if let Some(ts) = linked_node.get_viewbox_transform() {
use_node.append_transform(ts);
}
}
let new_node = doc.copy_node_deep(linked_node.clone());
for child in new_node.children() {
use_node.append(child);
}
let new_g_node = super::clip_element::clip_element(doc, use_node);
if let Some(mut g_node) = new_g_node {
g_node.set_attribute((AId::Transform, orig_ts));
} else {
use_node.prepend_transform(orig_ts);
}
}