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