svgdom/
node.rs

1use std::iter::FilterMap;
2use std::cell::{Ref, RefMut};
3
4use crate::{
5    tree,
6    Attribute,
7    AttributeId,
8    AttributeQName,
9    AttributeQNameRef,
10    Attributes,
11    AttributeValue,
12    ElementId,
13    Error,
14    NodeData,
15    NodeType,
16    PaintFallback,
17    QName,
18    QNameRef,
19    TagName,
20    TagNameRef,
21};
22
23impl<'a, N, V> From<(N, V)> for Attribute
24    where AttributeQNameRef<'a>: From<N>, AttributeValue: From<V>
25{
26    fn from(v: (N, V)) -> Self {
27        Attribute::new(v.0, v.1)
28    }
29}
30
31impl<'a, N> From<(N, Node)> for Attribute
32    where AttributeQNameRef<'a>: From<N>, N: Clone
33{
34    fn from(v: (N, Node)) -> Self {
35        let n = AttributeQNameRef::from(v.0.clone());
36
37        if n.has_id(AttributeId::Href) {
38            Attribute::new(v.0, AttributeValue::Link(v.1))
39        } else if n.has_id(AttributeId::Fill) || n.has_id(AttributeId::Stroke) {
40            Attribute::new(v.0, AttributeValue::Paint(v.1, None))
41        } else {
42            Attribute::new(v.0, AttributeValue::FuncLink(v.1))
43        }
44    }
45}
46
47impl<'a, N> From<(N, (Node, Option<PaintFallback>))> for Attribute
48    where AttributeQNameRef<'a>: From<N>, N: Clone
49{
50    fn from(v: (N, (Node, Option<PaintFallback>))) -> Self {
51        Attribute::new(v.0, AttributeValue::Paint((v.1).0, (v.1).1))
52    }
53}
54
55
56/// Representation of the SVG node.
57///
58/// This is the main block of the library.
59///
60/// It's designed as classical DOM node. It has links to a parent node, first child, last child,
61/// previous sibling and next sibling. So DOM nodes manipulations are very fast.
62///
63/// Node consists of:
64///
65/// - The [`NodeType`], which indicates it's type. It can't be changed.
66/// - Optional [`TagName`], used only by element nodes.
67/// - Unique ID of the `Element` node. Can be set to nodes with other types,
68///   but without any affect.
69/// - [`Attributes`] - list of [`Attribute`]s.
70/// - List of linked nodes. [Details.](#method.set_attribute_checked)
71/// - Text data, which is used by non-element nodes. Empty by default.
72///
73/// [`Attribute`]: struct.Attribute.html
74/// [`Attributes`]: struct.Attributes.html
75/// [`NodeType`]: enum.NodeType.html
76/// [`TagName`]: type.TagName.html
77pub type Node = tree::Node<NodeData>;
78
79impl Node {
80    /// Returns `true` if the node has a parent node.
81    ///
82    /// This method ignores root node.
83    ///
84    /// # Panics
85    ///
86    /// Panics if the node is currently mutably borrowed.
87    ///
88    /// # Examples
89    /// ```
90    /// use svgdom::Document;
91    ///
92    /// let doc = Document::from_str(
93    /// "<svg xmlns='http://www.w3.org/2000/svg'>
94    ///     <rect/>
95    /// </svg>").unwrap();
96    ///
97    /// let svg = doc.root().first_child().unwrap();
98    /// let rect = svg.first_child().unwrap();
99    /// assert_eq!(svg.has_parent(), false);
100    /// assert_eq!(rect.has_parent(), true);
101    /// ```
102    pub fn has_parent(&self) -> bool {
103        match self.parent() {
104            Some(node) => !node.is_root(),
105            None => false,
106        }
107    }
108
109    /// Returns node's type.
110    ///
111    /// You can't change the type of the node. Only create a new one.
112    ///
113    /// # Panics
114    ///
115    /// Panics if the node is currently mutably borrowed.
116    pub fn node_type(&self) -> NodeType {
117        self.borrow().node_type
118    }
119
120    /// Returns `true` if current node is a Root node.
121    ///
122    /// # Panics
123    ///
124    /// Panics if the node is currently mutably borrowed.
125    pub fn is_root(&self) -> bool {
126        self.node_type() == NodeType::Root
127    }
128
129    /// Returns `true` if current node is an Element node.
130    ///
131    /// # Panics
132    ///
133    /// Panics if the node is currently mutably borrowed.
134    pub fn is_element(&self) -> bool {
135        self.node_type() == NodeType::Element
136    }
137
138    /// Returns `true` if current node is a Comment node.
139    ///
140    /// # Panics
141    ///
142    /// Panics if the node is currently mutably borrowed.
143    pub fn is_comment(&self) -> bool {
144        self.node_type() == NodeType::Comment
145    }
146
147    /// Returns `true` if current node is a Text node.
148    ///
149    /// # Panics
150    ///
151    /// Panics if the node is currently mutably borrowed.
152    pub fn is_text(&self) -> bool {
153        self.node_type() == NodeType::Text
154    }
155
156    /// Checks that node belongs to any `Document`.
157    ///
158    /// # Panics
159    ///
160    /// Panics if the node is currently mutably borrowed.
161    pub fn is_detached(&self) -> bool {
162        self.borrow().storage_key.is_none()
163    }
164
165    /// Returns a text data of the node.
166    ///
167    /// Nodes with `Element` type can't contain text data.
168    ///
169    /// # Panics
170    ///
171    /// Panics if the node is currently mutably borrowed.
172    pub fn text(&self) -> Ref<String> {
173        Ref::map(self.borrow(), |d| &d.text)
174    }
175
176    /// Returns a mutable text data of the node.
177    ///
178    /// Nodes with `Element` type can't contain text data.
179    ///
180    /// # Panics
181    ///
182    /// Panics if the node is currently mutably borrowed.
183    pub fn text_mut(&mut self) -> RefMut<String> {
184        RefMut::map(self.borrow_mut(), |d| &mut d.text)
185    }
186
187    /// Sets a text data to the node.
188    ///
189    /// # Panics
190    ///
191    /// Panics if the node is currently mutably borrowed.
192    pub fn set_text(&mut self, text: &str) {
193        debug_assert_ne!(self.node_type(), NodeType::Element);
194        self.borrow_mut().text = text.to_owned();
195    }
196
197    /// Returns an ID of the element node.
198    ///
199    /// # Panics
200    ///
201    /// Panics if the node is currently mutably borrowed.
202    pub fn id(&self) -> Ref<String> {
203        Ref::map(self.borrow(), |d| &d.id)
204    }
205
206    /// Returns `true` if node has a not empty ID.
207    ///
208    /// # Panics
209    ///
210    /// Panics if the node is currently mutably borrowed.
211    pub fn has_id(&self) -> bool {
212        !self.id().is_empty()
213    }
214
215    /// Sets an ID of the element.
216    ///
217    /// Only element nodes can contain an ID.
218    ///
219    /// # Panics
220    ///
221    /// Panics if the node is currently borrowed.
222    pub fn set_id<S: Into<String>>(&mut self, id: S) {
223        // TODO: check that it's unique.
224        debug_assert_eq!(self.node_type(), NodeType::Element);
225        self.borrow_mut().id = id.into().to_owned();
226
227    }
228
229    /// Returns `true` if node has an `Element` type and an SVG tag name.
230    ///
231    /// # Panics
232    ///
233    /// Panics if the node is currently mutably borrowed.
234    pub fn is_svg_element(&self) -> bool {
235        if !self.is_element() {
236            return false;
237        }
238
239        match self.borrow().tag_name {
240            QName::Id(_) => true,
241            QName::Name(_) => false,
242        }
243    }
244
245    /// Returns a tag name of the element node.
246    ///
247    /// # Panics
248    ///
249    /// Panics if the node is currently mutably borrowed.
250    pub fn tag_name(&self) -> Ref<TagName> {
251        Ref::map(self.borrow(), |d| &d.tag_name)
252    }
253
254    /// Returns a tag name id of the SVG element node.
255    ///
256    /// # Panics
257    ///
258    /// Panics if the node is currently mutably borrowed.
259    pub fn tag_id(&self) -> Option<ElementId> {
260        match self.borrow().tag_name {
261            QName::Id(id) => Some(id),
262            QName::Name(_) => None,
263        }
264    }
265
266    /// Returns `true` if node has the same tag name as supplied.
267    ///
268    /// # Panics
269    ///
270    /// Panics if the node is currently mutably borrowed.
271    pub fn has_tag_name<'a, T>(&self, tag_name: T) -> bool
272        where TagNameRef<'a>: From<T>
273    {
274        self.borrow().tag_name.as_ref() == TagNameRef::from(tag_name)
275    }
276
277    /// Sets a tag name of the element node.
278    ///
279    /// Only element nodes can contain tag name.
280    ///
281    /// # Panics
282    ///
283    /// - Panics if the node is currently borrowed.
284    /// - Panics if a string tag name is empty.
285    pub fn set_tag_name<'a, T>(&mut self, tag_name: T)
286        where TagNameRef<'a>: From<T>
287    {
288        debug_assert_eq!(self.node_type(), NodeType::Element);
289
290        let tn = TagNameRef::from(tag_name);
291        if let QNameRef::Name(name) = tn {
292            if name.is_empty() {
293                panic!("supplied tag name is empty");
294            }
295        }
296
297        self.borrow_mut().tag_name = TagName::from(tn);
298    }
299
300    /// Returns a reference to the `Attributes` of the current node.
301    ///
302    /// # Panics
303    ///
304    /// Panics if the node is currently mutably borrowed.
305    pub fn attributes(&self) -> Ref<Attributes> {
306        Ref::map(self.borrow(), |d| &d.attributes)
307    }
308
309    /// Returns a mutable reference to the `Attributes` of the current node.
310    ///
311    /// # Panics
312    ///
313    /// Panics if the node is currently borrowed.
314    pub fn attributes_mut(&mut self) -> RefMut<Attributes> {
315        RefMut::map(self.borrow_mut(), |d| &mut d.attributes)
316    }
317
318    /// Returns `true` if the node has an attribute with such `id`.
319    ///
320    /// # Panics
321    ///
322    /// Panics if the node is currently mutably borrowed.
323    #[inline]
324    pub fn has_attribute<'a, N>(&self, name: N) -> bool
325        where AttributeQNameRef<'a>: From<N>
326    {
327        self.borrow().attributes.contains(name)
328    }
329
330    /// Inserts a new attribute into attributes list.
331    ///
332    /// Unwrapped version of the [`set_attribute_checked`] method.
333    ///
334    /// # Panics
335    ///
336    /// Will panic on any error produced by the [`set_attribute_checked`] method.
337    ///
338    /// [`set_attribute_checked`]: #method.set_attribute_checked
339    pub fn set_attribute<T>(&mut self, v: T)
340        where T: Into<Attribute>
341    {
342        self.set_attribute_checked(v).unwrap();
343    }
344
345    /// Inserts a new attribute into attributes list.
346    ///
347    /// You can set attribute using one of the possible combinations:
348    ///
349    /// - ([`AttributeId`]/`&str`, [`AttributeValue`])
350    /// - ([`AttributeId`], [`Node`])
351    /// - [`Attribute`]
352    ///
353    /// [`AttributeId`]: enum.AttributeId.html
354    /// [`Attribute`]: struct.Attribute.html
355    /// [`Node`]: type.Node.html
356    /// [`AttributeValue`]: enum.AttributeValue.html
357    ///
358    /// This method will overwrite an existing attribute with the same name.
359    ///
360    /// # Errors
361    ///
362    /// - [`ElementMustHaveAnId`]
363    /// - [`ElementCrosslink`]
364    ///
365    /// # Panics
366    ///
367    /// Panics if the node is currently borrowed.
368    ///
369    /// # Examples
370    ///
371    /// Ways to specify attributes:
372    ///
373    /// ```
374    /// use svgdom::{
375    ///     Document,
376    ///     Attribute,
377    ///     AttributeId as AId,
378    ///     ElementId as EId,
379    /// };
380    ///
381    /// // Create a simple document.
382    /// let mut doc = Document::new();
383    /// let mut svg = doc.create_element(EId::Svg);
384    /// let mut rect = doc.create_element(EId::Rect);
385    ///
386    /// doc.root().append(svg.clone());
387    /// svg.append(rect.clone());
388    ///
389    /// // In order to set element as an attribute value, we must set id first.
390    /// rect.set_id("rect1");
391    ///
392    /// // Using predefined attribute name.
393    /// svg.set_attribute((AId::X, 1.0));
394    /// svg.set_attribute((AId::X, "random text"));
395    /// // Using custom attribute name.
396    /// svg.set_attribute(("non-svg-attr", 1.0));
397    /// // Using existing attribute object.
398    /// svg.set_attribute(Attribute::new(AId::X, 1.0));
399    /// svg.set_attribute(Attribute::new("non-svg-attr", 1.0));
400    /// // Using an existing node as an attribute value.
401    /// svg.set_attribute((AId::Href, rect));
402    /// ```
403    ///
404    /// Linked attributes:
405    ///
406    /// ```
407    /// use svgdom::{
408    ///     Document,
409    ///     AttributeId as AId,
410    ///     ElementId as EId,
411    ///     AttributeValue,
412    /// };
413    ///
414    /// // Create a simple document.
415    /// let mut doc = Document::new();
416    /// let mut gradient = doc.create_element(EId::LinearGradient);
417    /// let mut rect = doc.create_element(EId::Rect);
418    ///
419    /// doc.root().append(gradient.clone());
420    /// doc.root().append(rect.clone());
421    ///
422    /// gradient.set_id("lg1");
423    /// rect.set_id("rect1");
424    ///
425    /// // Set a `fill` attribute value to the `none`.
426    /// // For now everything like in any other XML DOM library.
427    /// rect.set_attribute((AId::Fill, AttributeValue::None));
428    ///
429    /// // Now we want to fill our rect with a gradient.
430    /// // To do this we need to set a link attribute:
431    /// rect.set_attribute((AId::Fill, gradient.clone()));
432    ///
433    /// // Now our fill attribute has a link to the `gradient` node.
434    /// // Not as text, aka `url(#lg1)`, but as actual reference.
435    ///
436    /// // This adds support for fast checking that the element is used. Which is very useful.
437    ///
438    /// // `gradient` is now used, since we link it.
439    /// assert_eq!(gradient.is_used(), true);
440    /// // Also, we can check how many elements are uses this `gradient`.
441    /// assert_eq!(gradient.uses_count(), 1);
442    /// // And even get this elements.
443    /// assert_eq!(gradient.linked_nodes()[0], rect);
444    ///
445    /// // And now, if we remove our `rect` - `gradient` will became unused again.
446    /// doc.remove_node(rect);
447    /// assert_eq!(gradient.is_used(), false);
448    /// ```
449    ///
450    /// [`ElementMustHaveAnId`]: enum.Error.html
451    /// [`ElementCrosslink`]: enum.Error.html
452    pub fn set_attribute_checked<T>(&mut self, v: T) -> Result<(), Error>
453        where T: Into<Attribute>
454    {
455        self.set_attribute_checked_impl(v.into())
456    }
457
458    fn set_attribute_checked_impl(&mut self, attr: Attribute) -> Result<(), Error> {
459        debug_assert!(self.node_type() == NodeType::Element);
460
461        match attr.value {
462              AttributeValue::Link(ref iri)
463            | AttributeValue::FuncLink(ref iri) => {
464                self.set_link_attribute(attr.name, iri.clone(), None)?;
465                return Ok(());
466            }
467            AttributeValue::Paint(ref iri, fallback) => {
468                self.set_link_attribute(attr.name, iri.clone(), fallback)?;
469                return Ok(());
470            }
471            _ => {}
472        }
473
474        self.set_simple_attribute(attr);
475
476        Ok(())
477    }
478
479    fn set_simple_attribute(&mut self, attr: Attribute) {
480        debug_assert!(!attr.is_link_container());
481
482        // we must remove existing attribute to prevent dangling links
483        self.remove_attribute(attr.name.as_ref());
484
485        let mut attrs = self.attributes_mut();
486        attrs.insert(attr);
487    }
488
489    fn set_link_attribute(
490        &mut self,
491        name: AttributeQName,
492        mut node: Node,
493        fallback: Option<PaintFallback>,
494    ) -> Result<(), Error> {
495        if node.id().is_empty() {
496            return Err(Error::ElementMustHaveAnId);
497        }
498
499        // check for recursion
500        if *self.id() == *node.id() {
501            return Err(Error::ElementCrosslink);
502        }
503
504        // check for recursion 2
505        if self.linked_nodes().iter().any(|n| *n == node) {
506            return Err(Error::ElementCrosslink);
507        }
508
509        // we must remove existing attribute to prevent dangling links
510        self.remove_attribute(name.as_ref());
511
512        {
513            let a = if name.has_id(AttributeId::Href) {
514                Attribute::new(name.as_ref(), AttributeValue::Link(node.clone()))
515            } else if name.has_id(AttributeId::Fill) || name.has_id(AttributeId::Stroke) {
516                Attribute::new(name.as_ref(), AttributeValue::Paint(node.clone(), fallback))
517            } else {
518                Attribute::new(name.as_ref(), AttributeValue::FuncLink(node.clone()))
519            };
520
521            let mut attributes = self.attributes_mut();
522            attributes.insert(a);
523        }
524
525        node.borrow_mut().linked_nodes.push(self.clone());
526
527        Ok(())
528    }
529
530    /// Inserts a new attribute into attributes list if it doesn't contain one.
531    ///
532    /// `value` will be cloned if needed.
533    ///
534    /// Shorthand for:
535    ///
536    /// ```ignore
537    /// if !node.has_attribute(...) {
538    ///     node.set_attribute(...);
539    /// }
540    /// ```
541    ///
542    /// # Panics
543    ///
544    /// Will panic on any error produced by the [`set_attribute_checked`] method.
545    ///
546    /// [`set_attribute_checked`]: #method.set_attribute_checked
547    pub fn set_attribute_if_none<'a, T>(&mut self, v: T)
548        where T: Into<Attribute>
549    {
550        let attr: Attribute = v.into();
551        if !self.has_attribute(attr.name.as_ref()) {
552            self.set_attribute(attr);
553        }
554    }
555
556    /// Removes an attribute from the node.
557    ///
558    /// It will also unlink it, if it was an referenced attribute.
559    ///
560    /// # Panics
561    ///
562    /// Panics if the node is currently borrowed.
563    pub fn remove_attribute<'a, N>(&mut self, name: N)
564        where AttributeQNameRef<'a>: From<N>, N: Copy
565    {
566        if !self.has_attribute(name) {
567            return;
568        }
569
570        // we must unlink referenced attributes
571        if let Some(value) = self.attributes().get_value(name) {
572            match *value {
573                  AttributeValue::Link(ref node)
574                | AttributeValue::FuncLink(ref node)
575                | AttributeValue::Paint(ref node, _) => {
576                    let mut node = node.clone();
577
578                    // this code can't panic, because we know that such node exist
579                    let index = node.borrow().linked_nodes.iter().position(|n| n == self).unwrap();
580                    node.borrow_mut().linked_nodes.remove(index);
581                }
582                _ => {}
583            }
584        }
585
586        self.attributes_mut().remove(name);
587    }
588
589    /// Returns an iterator over linked nodes.
590    ///
591    /// See [Node::set_attribute()](#method.set_attribute) for details.
592    ///
593    /// # Panics
594    ///
595    /// Panics if the node is currently mutably borrowed.
596    pub fn linked_nodes(&self) -> Ref<Vec<Node>> {
597        Ref::map(self.borrow(), |d| &d.linked_nodes)
598    }
599
600    /// Returns an iterator over mutable linked nodes.
601    ///
602    /// See [Node::set_attribute()](#method.set_attribute) for details.
603    ///
604    /// # Panics
605    ///
606    /// Panics if the node is currently mutably borrowed.
607    pub fn linked_nodes_mut(&mut self) -> RefMut<Vec<Node>> {
608        RefMut::map(self.borrow_mut(), |d| &mut d.linked_nodes)
609    }
610
611    /// Returns `true` if the current node is linked to any of the DOM nodes.
612    ///
613    /// See [Node::set_attribute()](#method.set_attribute) for details.
614    ///
615    /// # Panics
616    ///
617    /// Panics if the node is currently mutably borrowed.
618    pub fn is_used(&self) -> bool {
619        !self.linked_nodes().is_empty()
620    }
621
622    /// Returns a number of nodes, which is linked to this node.
623    ///
624    /// See [Node::set_attribute()](#method.set_attribute) for details.
625    ///
626    /// # Panics
627    ///
628    /// Panics if the node is currently mutably borrowed.
629    pub fn uses_count(&self) -> usize {
630        self.linked_nodes().len()
631    }
632}
633
634/// An iterator over SVG elements.
635pub trait FilterSvg: Iterator {
636    /// Filters SVG elements.
637    fn svg(self) -> FilterMap<Self, fn(Node) -> Option<(ElementId, Node)>>
638        where Self: Iterator<Item = Node> + Sized,
639    {
640        fn is_svg(node: Node) -> Option<(ElementId, Node)> {
641            if let QName::Id(id) = *node.tag_name() {
642                return Some((id, node.clone()));
643            }
644
645            None
646        }
647
648        self.filter_map(is_svg)
649    }
650}
651
652impl<'a, I: Iterator<Item = Node>> FilterSvg for I {}