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 {}