1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 
5 use std::fmt;
6 use std::collections::HashMap;
7 
8 use log::warn;
9 
10 use svgtypes::FuzzyEq;
11 
12 use crate::geom::Rect;
13 use crate::tree;
14 
15 mod parse;
16 pub use parse::*;
17 
18 mod names;
19 pub use names::*;
20 
21 type Range = std::ops::Range<usize>;
22 
23 
24 pub struct Document {
25     nodes: Vec<NodeData>,
26     attrs: Vec<Attribute>,
27     links: HashMap<String, NodeId>,
28 }
29 
30 impl Document {
31     #[inline]
root(&self) -> Node32     pub fn root(&self) -> Node {
33         Node { id: NodeId(0), d: &self.nodes[0], doc: self }
34     }
35 
root_element(&self) -> Node36     pub fn root_element(&self) -> Node {
37         // `unwrap` is safe, because `Document` is guarantee to have at least one element.
38         self.root().first_element_child().unwrap()
39     }
40 
descendants(&self) -> Descendants41     pub fn descendants(&self) -> Descendants {
42         self.root().descendants()
43     }
44 
45     #[inline]
element_by_id(&self, id: &str) -> Option<Node>46     pub fn element_by_id(&self, id: &str) -> Option<Node> {
47         let node_id = self.links.get(id)?;
48         Some(self.get(*node_id))
49     }
50 
51     #[inline]
get(&self, id: NodeId) -> Node52     pub fn get(&self, id: NodeId) -> Node {
53         Node { id, d: &self.nodes[id.0], doc: self }
54     }
55 }
56 
57 impl fmt::Debug for Document {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>58     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
59         if !self.root().has_children() {
60             return write!(f, "Document []");
61         }
62 
63         macro_rules! writeln_indented {
64             ($depth:expr, $f:expr, $fmt:expr) => {
65                 for _ in 0..$depth { write!($f, "    ")?; }
66                 writeln!($f, $fmt)?;
67             };
68             ($depth:expr, $f:expr, $fmt:expr, $($arg:tt)*) => {
69                 for _ in 0..$depth { write!($f, "    ")?; }
70                 writeln!($f, $fmt, $($arg)*)?;
71             };
72         }
73 
74         fn print_children(parent: Node, depth: usize, f: &mut fmt::Formatter)
75             -> Result<(), fmt::Error>
76         {
77             for child in parent.children() {
78                 if child.is_element() {
79                     writeln_indented!(depth, f, "Element {{");
80                     writeln_indented!(depth, f, "    tag_name: {:?}", child.tag_name());
81 
82                     if !child.attributes().is_empty() {
83                         writeln_indented!(depth + 1, f, "attributes: [");
84                         for attr in child.attributes() {
85                             writeln_indented!(depth + 2, f, "{:?}", attr);
86                         }
87                         writeln_indented!(depth + 1, f, "]");
88                     }
89 
90                     if child.has_children() {
91                         writeln_indented!(depth, f, "    children: [");
92                         print_children(child, depth + 2, f)?;
93                         writeln_indented!(depth, f, "    ]");
94                     }
95 
96                     writeln_indented!(depth, f, "}}");
97                 } else {
98                     writeln_indented!(depth, f, "{:?}", child);
99                 }
100             }
101 
102             Ok(())
103         }
104 
105         writeln!(f, "Document [")?;
106         print_children(self.root(), 1, f)?;
107         writeln!(f, "]")?;
108 
109         Ok(())
110     }
111 }
112 
113 
114 #[derive(Clone, Copy, PartialEq, Debug)]
115 pub struct NodeId(usize);
116 
117 #[derive(Clone, Copy, PartialEq, Debug)]
118 struct AttributeId(usize);
119 
120 
121 enum NodeKind {
122     Root,
123     Element {
124         tag_name: EId,
125         attributes: Range,
126     },
127     Text(String),
128 }
129 
130 
131 struct NodeData {
132     parent: Option<NodeId>,
133     prev_sibling: Option<NodeId>,
134     next_sibling: Option<NodeId>,
135     children: Option<(NodeId, NodeId)>,
136     kind: NodeKind,
137 }
138 
139 #[derive(Clone, Debug)]
140 pub enum AttributeValue {
141     None,
142     CurrentColor,
143     Angle(svgtypes::Angle),
144     AspectRatio(svgtypes::AspectRatio),
145     Color(svgtypes::Color),
146     EnableBackground(tree::EnableBackground),
147     Length(svgtypes::Length),
148     Link(String),
149     Number(f64),
150     NumberList(svgtypes::NumberList),
151     Opacity(tree::Opacity),
152     Paint(String, Option<svgtypes::PaintFallback>),
153     Path(tree::SharedPathData),
154     String(String),
155     Transform(svgtypes::Transform),
156     ViewBox(svgtypes::ViewBox),
157 }
158 
159 #[derive(Clone)]
160 pub struct Attribute {
161     pub name: AId,
162     pub value: AttributeValue,
163 }
164 
165 impl fmt::Debug for Attribute {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>166     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
167         write!(f, "Attribute {{ name: {:?}, value: {:?} }}", self.name, self.value)
168     }
169 }
170 
171 
172 #[derive(Clone, Copy)]
173 pub struct Node<'a> {
174     id: NodeId,
175     doc: &'a Document,
176     d: &'a NodeData,
177 }
178 
179 impl Eq for Node<'_> {}
180 
181 impl PartialEq for Node<'_> {
182     #[inline]
eq(&self, other: &Self) -> bool183     fn eq(&self, other: &Self) -> bool {
184            self.id == other.id
185         && self.doc as *const _ == other.doc as *const _
186         && self.d as *const _ == other.d as *const _
187     }
188 }
189 
190 impl<'a> Node<'a> {
191     #[inline]
id(&self) -> NodeId192     pub fn id(&self) -> NodeId {
193         self.id
194     }
195 
196     #[allow(dead_code)]
197     #[inline]
is_root(&self) -> bool198     pub fn is_root(&self) -> bool {
199         match self.d.kind {
200             NodeKind::Root => true,
201             _ => false,
202         }
203     }
204 
205     #[inline]
is_element(&self) -> bool206     pub fn is_element(&self) -> bool {
207         match self.d.kind {
208             NodeKind::Element { .. } => true,
209             _ => false,
210         }
211     }
212 
213     #[inline]
is_text(&self) -> bool214     pub fn is_text(&self) -> bool {
215         match self.d.kind {
216             NodeKind::Text(_) => true,
217             _ => false,
218         }
219     }
220 
221     #[inline]
document(&self) -> &'a Document222     pub fn document(&self) -> &'a Document {
223         self.doc
224     }
225 
226     #[inline]
tag_name(&self) -> Option<EId>227     pub fn tag_name(&self) -> Option<EId> {
228         match self.d.kind {
229             NodeKind::Element { tag_name, .. } => Some(tag_name),
230             _ => None,
231         }
232     }
233 
234     #[inline]
has_tag_name(&self, name: EId) -> bool235     pub fn has_tag_name(&self, name: EId) -> bool {
236         match self.d.kind {
237             NodeKind::Element { tag_name, .. } => tag_name == name,
238             _ => false,
239         }
240     }
241 
element_id(&self) -> &str242     pub fn element_id(&self) -> &str {
243         self.attribute(AId::Id).unwrap_or("")
244     }
245 
has_element_id(&self) -> bool246     pub fn has_element_id(&self) -> bool {
247         !self.element_id().is_empty()
248     }
249 
250     #[inline(never)]
attribute<V: FromValue<'a>>(&self, aid: AId) -> Option<V>251     pub fn attribute<V: FromValue<'a>>(&self, aid: AId) -> Option<V> {
252         FromValue::get(*self, aid)
253     }
254 
has_attribute(&self, aid: AId) -> bool255     pub fn has_attribute(&self, aid: AId) -> bool {
256         self.attributes().iter().any(|a| a.name == aid)
257     }
258 
attributes(&self) -> &'a [Attribute]259     pub fn attributes(&self) -> &'a [Attribute] {
260         match self.d.kind {
261             NodeKind::Element { ref attributes, .. } => &self.doc.attrs[attributes.clone()],
262             _ => &[],
263         }
264     }
265 
attribute_id(&self, aid: AId) -> Option<AttributeId>266     fn attribute_id(&self, aid: AId) -> Option<AttributeId> {
267         match self.d.kind {
268             NodeKind::Element { ref attributes, .. } => {
269                 let idx = self.attributes().iter().position(|attr| attr.name == aid)?;
270                 Some(AttributeId(attributes.start + idx))
271             }
272             _ => None,
273         }
274     }
275 
find_attribute<V: FromValue<'a>>(&self, aid: AId) -> Option<V>276     pub fn find_attribute<V: FromValue<'a>>(&self, aid: AId) -> Option<V> {
277         self.find_attribute_impl(aid).and_then(|n| n.attribute(aid))
278     }
279 
find_attribute_impl(&self, aid: AId) -> Option<Node<'a>>280     fn find_attribute_impl(&self, aid: AId) -> Option<Node<'a>> {
281         if aid.is_inheritable() {
282             for n in self.ancestors() {
283                 if n.has_attribute(aid) {
284                     return Some(n);
285                 }
286             }
287 
288             None
289         } else {
290             if self.has_attribute(aid) {
291                 Some(*self)
292             } else {
293                 let n = self.parent_element()?;
294                 if n.has_attribute(aid) {
295                     Some(n)
296                 } else {
297                     None
298                 }
299             }
300         }
301     }
302 
find_node_with_attribute(&self, aid: AId) -> Option<Node>303     pub fn find_node_with_attribute(&self, aid: AId) -> Option<Node> {
304         self.ancestors().find(|n| n.has_attribute(aid))
305     }
306 
has_valid_transform(&self, aid: AId) -> bool307     pub fn has_valid_transform(&self, aid: AId) -> bool {
308         // Do not use Node::attribute::<Transform>, because it will always
309         // return a valid transform.
310 
311         let attr = match self.attributes().iter().find(|a| a.name == aid) {
312             Some(attr) => attr,
313             None => return true,
314         };
315 
316         if let AttributeValue::Transform(ref ts) = attr.value {
317             let (sx, sy) = ts.get_scale();
318             if sx.fuzzy_eq(&0.0) || sy.fuzzy_eq(&0.0) {
319                 return false;
320             }
321         }
322 
323         true
324     }
325 
get_viewbox(&self) -> Option<Rect>326     pub fn get_viewbox(&self) -> Option<Rect> {
327         let vb: svgtypes::ViewBox = self.attribute(AId::ViewBox)?;
328         Rect::new(vb.x, vb.y, vb.w, vb.h)
329     }
330 
text(&self) -> &'a str331     pub fn text(&self) -> &'a str {
332         match self.d.kind {
333             NodeKind::Element { .. } => {
334                 match self.first_child() {
335                     Some(child) if child.is_text() => {
336                         match self.doc.nodes[child.id.0].kind {
337                             NodeKind::Text(ref text) => text,
338                             _ => ""
339                         }
340                     }
341                     _ => "",
342                 }
343             }
344             NodeKind::Text(ref text) => text,
345             _ => "",
346         }
347     }
348 
349     #[inline]
gen_node(&self, id: NodeId) -> Node<'a>350     fn gen_node(&self, id: NodeId) -> Node<'a> {
351         Node { id, d: &self.doc.nodes[id.0], doc: self.doc }
352     }
353 
parent(&self) -> Option<Self>354     pub fn parent(&self) -> Option<Self> {
355         self.d.parent.map(|id| self.gen_node(id))
356     }
357 
parent_element(&self) -> Option<Self>358     pub fn parent_element(&self) -> Option<Self> {
359         self.ancestors().skip(1).filter(|n| n.is_element()).nth(0)
360     }
361 
prev_sibling(&self) -> Option<Self>362     pub fn prev_sibling(&self) -> Option<Self> {
363         self.d.prev_sibling.map(|id| self.gen_node(id))
364     }
365 
next_sibling(&self) -> Option<Self>366     pub fn next_sibling(&self) -> Option<Self> {
367         self.d.next_sibling.map(|id| self.gen_node(id))
368     }
369 
first_child(&self) -> Option<Self>370     pub fn first_child(&self) -> Option<Self> {
371         self.d.children.map(|(id, _)| self.gen_node(id))
372     }
373 
first_element_child(&self) -> Option<Self>374     pub fn first_element_child(&self) -> Option<Self> {
375         self.children().filter(|n| n.is_element()).nth(0)
376     }
377 
last_child(&self) -> Option<Self>378     pub fn last_child(&self) -> Option<Self> {
379         self.d.children.map(|(_, id)| self.gen_node(id))
380     }
381 
has_children(&self) -> bool382     pub fn has_children(&self) -> bool {
383         self.d.children.is_some()
384     }
385 
386     /// Returns an iterator over ancestor nodes starting at this node.
ancestors(&self) -> Ancestors<'a>387     pub fn ancestors(&self) -> Ancestors<'a> {
388         Ancestors(Some(*self))
389     }
390 
391     /// Returns an iterator over children nodes.
children(&self) -> Children<'a>392     pub fn children(&self) -> Children<'a> {
393         Children { front: self.first_child(), back: self.last_child() }
394     }
395 
396     /// Returns an iterator which traverses the subtree starting at this node.
traverse(&self) -> Traverse<'a>397     pub fn traverse(&self) -> Traverse<'a> {
398         Traverse { root: *self, edge: None }
399     }
400 
401     /// Returns an iterator over this node and its descendants.
descendants(&self) -> Descendants<'a>402     pub fn descendants(&self) -> Descendants<'a> {
403         Descendants(self.traverse())
404     }
405 
href_iter(&self) -> HrefIter406     pub fn href_iter(&self) -> HrefIter {
407         HrefIter {
408             doc: self.document(),
409             origin: self.id(),
410             curr: self.id(),
411             is_first: true,
412             is_finished: false,
413         }
414     }
415 }
416 
417 impl fmt::Debug for Node<'_> {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>418     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
419         match self.d.kind {
420             NodeKind::Root => write!(f, "Root"),
421             NodeKind::Element { .. } => {
422                 write!(f, "Element {{ tag_name: {:?}, attributes: {:?} }}",
423                        self.tag_name(), self.attributes())
424             }
425             NodeKind::Text(ref text) => write!(f, "Text({:?})", text),
426         }
427     }
428 }
429 
430 macro_rules! axis_iterators {
431     ($($i:ident($f:path);)*) => {
432         $(
433             #[derive(Clone)]
434             pub struct $i<'a>(Option<Node<'a>>);
435 
436             impl<'a> Iterator for $i<'a> {
437                 type Item = Node<'a>;
438 
439                 #[inline]
440                 fn next(&mut self) -> Option<Self::Item> {
441                     let node = self.0.take();
442                     self.0 = node.as_ref().and_then($f);
443                     node
444                 }
445             }
446         )*
447     };
448 }
449 
450 axis_iterators! {
451     Ancestors(Node::parent);
452     PrevSiblings(Node::prev_sibling);
453     NextSiblings(Node::next_sibling);
454 }
455 
456 
457 #[derive(Clone)]
458 pub struct Children<'a> {
459     front: Option<Node<'a>>,
460     back: Option<Node<'a>>,
461 }
462 
463 impl<'a> Iterator for Children<'a> {
464     type Item = Node<'a>;
465 
next(&mut self) -> Option<Self::Item>466     fn next(&mut self) -> Option<Self::Item> {
467         if self.front == self.back {
468             let node = self.front.take();
469             self.back = None;
470             node
471         } else {
472             let node = self.front.take();
473             self.front = node.as_ref().and_then(Node::next_sibling);
474             node
475         }
476     }
477 }
478 
479 impl<'a> DoubleEndedIterator for Children<'a> {
next_back(&mut self) -> Option<Self::Item>480     fn next_back(&mut self) -> Option<Self::Item> {
481         if self.back == self.front {
482             let node = self.back.take();
483             self.front = None;
484             node
485         } else {
486             let node = self.back.take();
487             self.back = node.as_ref().and_then(Node::prev_sibling);
488             node
489         }
490     }
491 }
492 
493 
494 #[derive(Clone, Copy, PartialEq, Debug)]
495 pub enum Edge<'a> {
496     Open(Node<'a>),
497     Close(Node<'a>),
498 }
499 
500 
501 #[derive(Clone)]
502 pub struct Traverse<'a> {
503     root: Node<'a>,
504     edge: Option<Edge<'a>>,
505 }
506 
507 impl<'a> Iterator for Traverse<'a> {
508     type Item = Edge<'a>;
509 
next(&mut self) -> Option<Self::Item>510     fn next(&mut self) -> Option<Self::Item> {
511         match self.edge {
512             Some(Edge::Open(node)) => {
513                 self.edge = Some(match node.first_child() {
514                     Some(first_child) => Edge::Open(first_child),
515                     None => Edge::Close(node),
516                 });
517             }
518             Some(Edge::Close(node)) => {
519                 if node == self.root {
520                     self.edge = None;
521                 } else if let Some(next_sibling) = node.next_sibling() {
522                     self.edge = Some(Edge::Open(next_sibling));
523                 } else {
524                     self.edge = node.parent().map(Edge::Close);
525                 }
526             }
527             None => {
528                 self.edge = Some(Edge::Open(self.root));
529             }
530         }
531 
532         self.edge
533     }
534 }
535 
536 
537 #[derive(Clone)]
538 pub struct Descendants<'a>(Traverse<'a>);
539 
540 impl<'a> Iterator for Descendants<'a> {
541     type Item = Node<'a>;
542 
543     #[inline]
next(&mut self) -> Option<Self::Item>544     fn next(&mut self) -> Option<Self::Item> {
545         for edge in &mut self.0 {
546             if let Edge::Open(node) = edge {
547                 return Some(node);
548             }
549         }
550 
551         None
552     }
553 }
554 
555 
556 pub struct HrefIter<'a> {
557     doc: &'a Document,
558     origin: NodeId,
559     curr: NodeId,
560     is_first: bool,
561     is_finished: bool,
562 }
563 
564 impl<'a> Iterator for HrefIter<'a> {
565     type Item = NodeId;
566 
next(&mut self) -> Option<Self::Item>567     fn next(&mut self) -> Option<Self::Item> {
568         if self.is_finished {
569             return None;
570         }
571 
572         if self.is_first {
573             self.is_first = false;
574             return Some(self.curr);
575         }
576 
577         if let Some(link) = self.doc.get(self.curr).attribute::<Node>(AId::Href) {
578             if link.id() == self.curr || link.id() == self.origin {
579                 warn!(
580                     "Element '#{}' cannot reference itself via 'xlink:href'.",
581                     self.doc.get(self.origin).element_id()
582                 );
583                 self.is_finished = true;
584                 return None;
585             }
586 
587             self.curr = link.id();
588             Some(link.id())
589         } else {
590             None
591         }
592     }
593 }
594 
595 
596 pub trait FromValue<'a>: Sized {
get(node: Node<'a>, aid: AId) -> Option<Self>597     fn get(node: Node<'a>, aid: AId) -> Option<Self>;
598 }
599 
600 macro_rules! impl_from_value {
601     ($rtype:ty, $etype:ident) => (
602         impl FromValue<'_> for $rtype {
603             fn get(node: Node, aid: AId) -> Option<Self> {
604                 let a = node.attributes().iter().find(|a| a.name == aid)?;
605                 if let AttributeValue::$etype(ref v) = a.value { Some(*v) } else { None }
606             }
607         }
608     )
609 }
610 
611 impl_from_value!(svgtypes::Color, Color);
612 impl_from_value!(svgtypes::Length, Length);
613 impl_from_value!(svgtypes::ViewBox, ViewBox);
614 impl_from_value!(svgtypes::AspectRatio, AspectRatio);
615 impl_from_value!(svgtypes::Angle, Angle);
616 impl_from_value!(f64, Number);
617 impl_from_value!(tree::Opacity, Opacity);
618 impl_from_value!(tree::EnableBackground, EnableBackground);
619 
620 impl<'a> FromValue<'a> for &'a AttributeValue {
get(node: Node<'a>, aid: AId) -> Option<Self>621     fn get(node: Node<'a>, aid: AId) -> Option<Self> {
622         node.attributes().iter().find(|a| a.name == aid).map(|a| &a.value)
623     }
624 }
625 
626 impl<'a> FromValue<'a> for svgtypes::Transform {
get(node: Node<'a>, aid: AId) -> Option<Self>627     fn get(node: Node<'a>, aid: AId) -> Option<Self> {
628         let a = node.attributes().iter().find(|a| a.name == aid)?;
629         let ts = match a.value {
630             AttributeValue::Transform(ref ts) => ts,
631             _ => return None,
632         };
633 
634         let (sx, sy) = ts.get_scale();
635         if sx.fuzzy_eq(&0.0) || sy.fuzzy_eq(&0.0) {
636             Some(svgtypes::Transform::default())
637         } else {
638             Some(*ts)
639         }
640     }
641 }
642 
643 impl FromValue<'_> for tree::SharedPathData {
get(node: Node, aid: AId) -> Option<Self>644     fn get(node: Node, aid: AId) -> Option<Self> {
645         let a = node.attributes().iter().find(|a| a.name == aid)?;
646         // Cloning is cheap, since it's a Rc.
647         if let AttributeValue::Path(ref v) = a.value { Some(v.clone()) } else { None }
648     }
649 }
650 
651 impl<'a> FromValue<'a> for &'a svgtypes::NumberList {
get(node: Node<'a>, aid: AId) -> Option<Self>652     fn get(node: Node<'a>, aid: AId) -> Option<Self> {
653         let a = node.attributes().iter().find(|a| a.name == aid)?;
654         if let AttributeValue::NumberList(ref v) = a.value { Some(v) } else { None }
655     }
656 }
657 
658 impl<'a> FromValue<'a> for &'a str {
get(node: Node<'a>, aid: AId) -> Option<Self>659     fn get(node: Node<'a>, aid: AId) -> Option<Self> {
660         let a = node.attributes().iter().find(|a| a.name == aid)?;
661         match a.value {
662             AttributeValue::None => {
663                 // A special case, because matching `None` is too verbose.
664                 //
665                 // match node.attribute(AId::Display) {
666                 //     Some(&svgtree::AttributeValue::None) => true,
667                 //     None => false,
668                 // }
669                 //
670                 // vs
671                 //
672                 // node.attribute(AId::Display) == Some("none")
673                 Some("none")
674             }
675             AttributeValue::String(ref v) => Some(v.as_str()),
676             _ => None,
677         }
678     }
679 }
680 
681 impl<'a> FromValue<'a> for Node<'a> {
get(node: Node<'a>, aid: AId) -> Option<Self>682     fn get(node: Node<'a>, aid: AId) -> Option<Self> {
683         let a = node.attributes().iter().find(|a| a.name == aid)?;
684         let id = match a.value  {
685             AttributeValue::Link(ref id) => id,
686             _ => return None,
687         };
688 
689         node.document().element_by_id(&id)
690     }
691 }
692 
693 pub trait EnumFromStr: Sized {
enum_from_str(text: &str) -> Option<Self>694     fn enum_from_str(text: &str) -> Option<Self>;
695 }
696 
697 impl<'a, T: EnumFromStr> FromValue<'a> for T {
698     #[inline]
get(node: Node, aid: AId) -> Option<Self>699     fn get(node: Node, aid: AId) -> Option<Self> {
700         EnumFromStr::enum_from_str(node.attribute(aid)?)
701     }
702 }
703 
704 
705 impl EId {
is_graphic(&self) -> bool706     pub fn is_graphic(&self) -> bool {
707         matches!(self,
708               EId::Circle
709             | EId::Ellipse
710             | EId::Image
711             | EId::Line
712             | EId::Path
713             | EId::Polygon
714             | EId::Polyline
715             | EId::Rect
716             | EId::Text
717             | EId::Use
718         )
719     }
720 
is_gradient(&self) -> bool721     pub fn is_gradient(&self) -> bool {
722         matches!(self,
723               EId::LinearGradient
724             | EId::RadialGradient
725         )
726     }
727 
is_paint_server(&self) -> bool728     pub fn is_paint_server(&self) -> bool {
729         matches!(self,
730               EId::LinearGradient
731             | EId::RadialGradient
732             | EId::Pattern
733         )
734     }
735 }
736 
737 impl AId {
is_presentation(&self) -> bool738     pub fn is_presentation(&self) -> bool {
739         matches!(self,
740               AId::BaselineShift
741             | AId::ClipPath
742             | AId::ClipRule
743             | AId::Color
744             | AId::ColorInterpolationFilters
745             | AId::Direction
746             | AId::Display
747             | AId::Fill
748             | AId::FillOpacity
749             | AId::FillRule
750             | AId::Filter
751             | AId::FloodColor
752             | AId::FloodOpacity
753             | AId::FontFamily
754             | AId::FontSize
755             | AId::FontStretch
756             | AId::FontStyle
757             | AId::FontVariant
758             | AId::FontWeight
759             | AId::ImageRendering
760             | AId::LetterSpacing
761             | AId::MarkerEnd
762             | AId::MarkerMid
763             | AId::MarkerStart
764             | AId::Mask
765             | AId::Opacity
766             | AId::Overflow
767             | AId::ShapeRendering
768             | AId::StopColor
769             | AId::StopOpacity
770             | AId::Stroke
771             | AId::StrokeDasharray
772             | AId::StrokeDashoffset
773             | AId::StrokeLinecap
774             | AId::StrokeLinejoin
775             | AId::StrokeMiterlimit
776             | AId::StrokeOpacity
777             | AId::StrokeWidth
778             | AId::TextAnchor
779             | AId::TextDecoration
780             | AId::TextRendering
781             | AId::Visibility
782             | AId::WordSpacing
783             | AId::WritingMode)
784     }
785 
is_inheritable(&self) -> bool786     pub fn is_inheritable(&self) -> bool {
787         if self.is_presentation() {
788             !is_non_inheritable(*self)
789         } else {
790             false
791         }
792     }
793 
allows_inherit_value(&self) -> bool794     pub fn allows_inherit_value(&self) -> bool {
795         matches!(self,
796               AId::BaselineShift
797             | AId::ClipPath
798             | AId::ClipRule
799             | AId::Color
800             | AId::ColorInterpolationFilters
801             | AId::Direction
802             | AId::Display
803             | AId::Fill
804             | AId::FillOpacity
805             | AId::FillRule
806             | AId::Filter
807             | AId::FloodColor
808             | AId::FloodOpacity
809             | AId::FontFamily
810             | AId::FontSize
811             | AId::FontStretch
812             | AId::FontStyle
813             | AId::FontVariant
814             | AId::FontWeight
815             | AId::ImageRendering
816             | AId::LetterSpacing
817             | AId::MarkerEnd
818             | AId::MarkerMid
819             | AId::MarkerStart
820             | AId::Mask
821             | AId::Opacity
822             | AId::Overflow
823             | AId::ShapeRendering
824             | AId::StopColor
825             | AId::StopOpacity
826             | AId::Stroke
827             | AId::StrokeDasharray
828             | AId::StrokeDashoffset
829             | AId::StrokeLinecap
830             | AId::StrokeLinejoin
831             | AId::StrokeMiterlimit
832             | AId::StrokeOpacity
833             | AId::StrokeWidth
834             | AId::TextAnchor
835             | AId::TextDecoration
836             | AId::TextRendering
837             | AId::Visibility
838             | AId::WordSpacing
839             | AId::WritingMode)
840     }
841 }
842 
is_non_inheritable(id: AId) -> bool843 fn is_non_inheritable(id: AId) -> bool {
844     matches!(id,
845           AId::BaselineShift
846         | AId::ClipPath
847         | AId::Display
848         | AId::Filter
849         | AId::FloodColor
850         | AId::FloodOpacity
851         | AId::Mask
852         | AId::Opacity
853         | AId::Overflow
854         | AId::StopColor
855         | AId::StopOpacity
856         | AId::TextDecoration)
857 }
858