use std::rc::Rc;
use svgrtypes::{Length, LengthUnit as Unit};
use crate::svgtree::{self, AId, EId};
use crate::{converter, Group, Node, NodeKind, OptionLog, Rect, Units};
#[derive(Clone, Debug)]
pub struct Mask {
pub id: String,
pub units: Units,
pub content_units: Units,
pub rect: Rect,
pub mask: Option<Rc<Self>>,
pub root: Node,
}
impl std::hash::Hash for Mask {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.units.hash(state);
self.content_units.hash(state);
self.rect.hash(state);
self.mask.hash(state);
}
}
pub(crate) fn convert(
node: svgtree::Node,
state: &converter::State,
cache: &mut converter::Cache,
) -> Option<Rc<Mask>> {
if !node.has_tag_name(EId::Mask) {
return None;
}
if let Some(mask) = cache.masks.get(node.element_id()) {
return Some(mask.clone());
}
let units = node
.attribute(AId::MaskUnits)
.unwrap_or(Units::ObjectBoundingBox);
let content_units = node
.attribute(AId::MaskContentUnits)
.unwrap_or(Units::UserSpaceOnUse);
let rect = Rect::new(
node.convert_length(AId::X, units, state, Length::new(-10.0, Unit::Percent)),
node.convert_length(AId::Y, units, state, Length::new(-10.0, Unit::Percent)),
node.convert_length(AId::Width, units, state, Length::new(120.0, Unit::Percent)),
node.convert_length(AId::Height, units, state, Length::new(120.0, Unit::Percent)),
);
let rect =
rect.log_none(|| log::warn!("Mask '{}' has an invalid size. Skipped.", node.element_id()))?;
let mut mask = None;
if let Some(link) = node.attribute::<svgtree::Node>(AId::Mask) {
mask = convert(link, state, cache);
if mask.is_none() {
return None;
}
}
let mut mask = Mask {
id: node.element_id().to_string(),
units,
content_units,
rect,
mask,
root: Node::new(NodeKind::Group(Group::default())),
};
converter::convert_children(node, state, cache, &mut mask.root);
if mask.root.has_children() {
let mask = Rc::new(mask);
cache
.masks
.insert(node.element_id().to_string(), mask.clone());
Some(mask)
} else {
None
}
}