usvg/tree/
mod.rs

1// Copyright 2019 the Resvg Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4pub mod filter;
5mod geom;
6mod text;
7
8use std::sync::Arc;
9
10pub use strict_num::{self, ApproxEqUlps, NonZeroPositiveF32, NormalizedF32, PositiveF32};
11
12pub use tiny_skia_path;
13
14pub use self::geom::*;
15pub use self::text::*;
16
17use crate::OptionLog;
18
19/// An alias to `NormalizedF32`.
20pub type Opacity = NormalizedF32;
21
22// Must not be clone-able to preserve ID uniqueness.
23#[derive(Debug)]
24pub(crate) struct NonEmptyString(String);
25
26impl NonEmptyString {
27    pub(crate) fn new(string: String) -> Option<Self> {
28        if string.trim().is_empty() {
29            return None;
30        }
31
32        Some(NonEmptyString(string))
33    }
34
35    pub(crate) fn get(&self) -> &str {
36        &self.0
37    }
38
39    pub(crate) fn take(self) -> String {
40        self.0
41    }
42}
43
44/// A non-zero `f32`.
45///
46/// Just like `f32` but immutable and guarantee to never be zero.
47#[derive(Clone, Copy, Debug)]
48pub struct NonZeroF32(f32);
49
50impl NonZeroF32 {
51    /// Creates a new `NonZeroF32` value.
52    #[inline]
53    pub fn new(n: f32) -> Option<Self> {
54        if n.approx_eq_ulps(&0.0, 4) {
55            None
56        } else {
57            Some(NonZeroF32(n))
58        }
59    }
60
61    /// Returns an underlying value.
62    #[inline]
63    pub fn get(&self) -> f32 {
64        self.0
65    }
66}
67
68#[derive(Clone, Copy, PartialEq, Debug)]
69pub(crate) enum Units {
70    UserSpaceOnUse,
71    ObjectBoundingBox,
72}
73
74// `Units` cannot have a default value, because it changes depending on an element.
75
76/// A visibility property.
77///
78/// `visibility` attribute in the SVG.
79#[allow(missing_docs)]
80#[derive(Clone, Copy, PartialEq, Debug)]
81pub(crate) enum Visibility {
82    Visible,
83    Hidden,
84    Collapse,
85}
86
87impl Default for Visibility {
88    fn default() -> Self {
89        Self::Visible
90    }
91}
92
93/// A shape rendering method.
94///
95/// `shape-rendering` attribute in the SVG.
96#[derive(Clone, Copy, PartialEq, Debug)]
97#[allow(missing_docs)]
98pub enum ShapeRendering {
99    OptimizeSpeed,
100    CrispEdges,
101    GeometricPrecision,
102}
103
104impl ShapeRendering {
105    /// Checks if anti-aliasing should be enabled.
106    pub fn use_shape_antialiasing(self) -> bool {
107        match self {
108            ShapeRendering::OptimizeSpeed => false,
109            ShapeRendering::CrispEdges => false,
110            ShapeRendering::GeometricPrecision => true,
111        }
112    }
113}
114
115impl Default for ShapeRendering {
116    fn default() -> Self {
117        Self::GeometricPrecision
118    }
119}
120
121impl std::str::FromStr for ShapeRendering {
122    type Err = &'static str;
123
124    fn from_str(s: &str) -> Result<Self, Self::Err> {
125        match s {
126            "optimizeSpeed" => Ok(ShapeRendering::OptimizeSpeed),
127            "crispEdges" => Ok(ShapeRendering::CrispEdges),
128            "geometricPrecision" => Ok(ShapeRendering::GeometricPrecision),
129            _ => Err("invalid"),
130        }
131    }
132}
133
134/// A text rendering method.
135///
136/// `text-rendering` attribute in the SVG.
137#[allow(missing_docs)]
138#[derive(Clone, Copy, PartialEq, Debug)]
139pub enum TextRendering {
140    OptimizeSpeed,
141    OptimizeLegibility,
142    GeometricPrecision,
143}
144
145impl Default for TextRendering {
146    fn default() -> Self {
147        Self::OptimizeLegibility
148    }
149}
150
151impl std::str::FromStr for TextRendering {
152    type Err = &'static str;
153
154    fn from_str(s: &str) -> Result<Self, Self::Err> {
155        match s {
156            "optimizeSpeed" => Ok(TextRendering::OptimizeSpeed),
157            "optimizeLegibility" => Ok(TextRendering::OptimizeLegibility),
158            "geometricPrecision" => Ok(TextRendering::GeometricPrecision),
159            _ => Err("invalid"),
160        }
161    }
162}
163
164/// An image rendering method.
165///
166/// `image-rendering` attribute in the SVG.
167#[allow(missing_docs)]
168#[derive(Clone, Copy, PartialEq, Debug)]
169pub enum ImageRendering {
170    OptimizeQuality,
171    OptimizeSpeed,
172    // The following can only appear as presentation attributes.
173    Smooth,
174    HighQuality,
175    CrispEdges,
176    Pixelated,
177}
178
179impl Default for ImageRendering {
180    fn default() -> Self {
181        Self::OptimizeQuality
182    }
183}
184
185impl std::str::FromStr for ImageRendering {
186    type Err = &'static str;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        match s {
190            "optimizeQuality" => Ok(ImageRendering::OptimizeQuality),
191            "optimizeSpeed" => Ok(ImageRendering::OptimizeSpeed),
192            "smooth" => Ok(ImageRendering::Smooth),
193            "high-quality" => Ok(ImageRendering::HighQuality),
194            "crisp-edges" => Ok(ImageRendering::CrispEdges),
195            "pixelated" => Ok(ImageRendering::Pixelated),
196            _ => Err("invalid"),
197        }
198    }
199}
200
201/// A blending mode property.
202///
203/// `mix-blend-mode` attribute in the SVG.
204#[allow(missing_docs)]
205#[derive(Clone, Copy, PartialEq, Debug)]
206pub enum BlendMode {
207    Normal,
208    Multiply,
209    Screen,
210    Overlay,
211    Darken,
212    Lighten,
213    ColorDodge,
214    ColorBurn,
215    HardLight,
216    SoftLight,
217    Difference,
218    Exclusion,
219    Hue,
220    Saturation,
221    Color,
222    Luminosity,
223}
224
225impl Default for BlendMode {
226    fn default() -> Self {
227        Self::Normal
228    }
229}
230
231/// A spread method.
232///
233/// `spreadMethod` attribute in the SVG.
234#[allow(missing_docs)]
235#[derive(Clone, Copy, PartialEq, Debug)]
236pub enum SpreadMethod {
237    Pad,
238    Reflect,
239    Repeat,
240}
241
242impl Default for SpreadMethod {
243    fn default() -> Self {
244        Self::Pad
245    }
246}
247
248/// A generic gradient.
249#[derive(Debug)]
250pub struct BaseGradient {
251    pub(crate) id: NonEmptyString,
252    pub(crate) units: Units, // used only during parsing
253    pub(crate) transform: Transform,
254    pub(crate) spread_method: SpreadMethod,
255    pub(crate) stops: Vec<Stop>,
256}
257
258impl BaseGradient {
259    /// Element's ID.
260    ///
261    /// Taken from the SVG itself.
262    /// Used only during SVG writing. `resvg` doesn't rely on this property.
263    pub fn id(&self) -> &str {
264        self.id.get()
265    }
266
267    /// Gradient transform.
268    ///
269    /// `gradientTransform` in SVG.
270    pub fn transform(&self) -> Transform {
271        self.transform
272    }
273
274    /// Gradient spreading method.
275    ///
276    /// `spreadMethod` in SVG.
277    pub fn spread_method(&self) -> SpreadMethod {
278        self.spread_method
279    }
280
281    /// A list of `stop` elements.
282    pub fn stops(&self) -> &[Stop] {
283        &self.stops
284    }
285}
286
287/// A linear gradient.
288///
289/// `linearGradient` element in SVG.
290#[derive(Debug)]
291pub struct LinearGradient {
292    pub(crate) base: BaseGradient,
293    pub(crate) x1: f32,
294    pub(crate) y1: f32,
295    pub(crate) x2: f32,
296    pub(crate) y2: f32,
297}
298
299impl LinearGradient {
300    /// `x1` coordinate.
301    pub fn x1(&self) -> f32 {
302        self.x1
303    }
304
305    /// `y1` coordinate.
306    pub fn y1(&self) -> f32 {
307        self.y1
308    }
309
310    /// `x2` coordinate.
311    pub fn x2(&self) -> f32 {
312        self.x2
313    }
314
315    /// `y2` coordinate.
316    pub fn y2(&self) -> f32 {
317        self.y2
318    }
319}
320
321impl std::ops::Deref for LinearGradient {
322    type Target = BaseGradient;
323
324    fn deref(&self) -> &Self::Target {
325        &self.base
326    }
327}
328
329/// A radial gradient.
330///
331/// `radialGradient` element in SVG.
332#[derive(Debug)]
333pub struct RadialGradient {
334    pub(crate) base: BaseGradient,
335    pub(crate) cx: f32,
336    pub(crate) cy: f32,
337    pub(crate) r: PositiveF32,
338    pub(crate) fx: f32,
339    pub(crate) fy: f32,
340}
341
342impl RadialGradient {
343    /// `cx` coordinate.
344    pub fn cx(&self) -> f32 {
345        self.cx
346    }
347
348    /// `cy` coordinate.
349    pub fn cy(&self) -> f32 {
350        self.cy
351    }
352
353    /// Gradient radius.
354    pub fn r(&self) -> PositiveF32 {
355        self.r
356    }
357
358    /// `fx` coordinate.
359    pub fn fx(&self) -> f32 {
360        self.fx
361    }
362
363    /// `fy` coordinate.
364    pub fn fy(&self) -> f32 {
365        self.fy
366    }
367}
368
369impl std::ops::Deref for RadialGradient {
370    type Target = BaseGradient;
371
372    fn deref(&self) -> &Self::Target {
373        &self.base
374    }
375}
376
377/// An alias to `NormalizedF32`.
378pub type StopOffset = NormalizedF32;
379
380/// Gradient's stop element.
381///
382/// `stop` element in SVG.
383#[derive(Clone, Copy, Debug)]
384pub struct Stop {
385    pub(crate) offset: StopOffset,
386    pub(crate) color: Color,
387    pub(crate) opacity: Opacity,
388}
389
390impl Stop {
391    /// Gradient stop offset.
392    ///
393    /// `offset` in SVG.
394    pub fn offset(&self) -> StopOffset {
395        self.offset
396    }
397
398    /// Gradient stop color.
399    ///
400    /// `stop-color` in SVG.
401    pub fn color(&self) -> Color {
402        self.color
403    }
404
405    /// Gradient stop opacity.
406    ///
407    /// `stop-opacity` in SVG.
408    pub fn opacity(&self) -> Opacity {
409        self.opacity
410    }
411}
412
413/// A pattern element.
414///
415/// `pattern` element in SVG.
416#[derive(Debug)]
417pub struct Pattern {
418    pub(crate) id: NonEmptyString,
419    pub(crate) units: Units,         // used only during parsing
420    pub(crate) content_units: Units, // used only during parsing
421    pub(crate) transform: Transform,
422    pub(crate) rect: NonZeroRect,
423    pub(crate) view_box: Option<ViewBox>,
424    pub(crate) root: Group,
425}
426
427impl Pattern {
428    /// Element's ID.
429    ///
430    /// Taken from the SVG itself.
431    /// Used only during SVG writing. `resvg` doesn't rely on this property.
432    pub fn id(&self) -> &str {
433        self.id.get()
434    }
435
436    /// Pattern transform.
437    ///
438    /// `patternTransform` in SVG.
439    pub fn transform(&self) -> Transform {
440        self.transform
441    }
442
443    /// Pattern rectangle.
444    ///
445    /// `x`, `y`, `width` and `height` in SVG.
446    pub fn rect(&self) -> NonZeroRect {
447        self.rect
448    }
449
450    /// Pattern children.
451    pub fn root(&self) -> &Group {
452        &self.root
453    }
454}
455
456/// An alias to `NonZeroPositiveF32`.
457pub type StrokeWidth = NonZeroPositiveF32;
458
459/// A `stroke-miterlimit` value.
460///
461/// Just like `f32` but immutable and guarantee to be >=1.0.
462#[derive(Clone, Copy, Debug)]
463pub struct StrokeMiterlimit(f32);
464
465impl StrokeMiterlimit {
466    /// Creates a new `StrokeMiterlimit` value.
467    #[inline]
468    pub fn new(n: f32) -> Self {
469        debug_assert!(n.is_finite());
470        debug_assert!(n >= 1.0);
471
472        let n = if !(n >= 1.0) { 1.0 } else { n };
473
474        StrokeMiterlimit(n)
475    }
476
477    /// Returns an underlying value.
478    #[inline]
479    pub fn get(&self) -> f32 {
480        self.0
481    }
482}
483
484impl Default for StrokeMiterlimit {
485    #[inline]
486    fn default() -> Self {
487        StrokeMiterlimit::new(4.0)
488    }
489}
490
491impl From<f32> for StrokeMiterlimit {
492    #[inline]
493    fn from(n: f32) -> Self {
494        Self::new(n)
495    }
496}
497
498impl PartialEq for StrokeMiterlimit {
499    #[inline]
500    fn eq(&self, other: &Self) -> bool {
501        self.0.approx_eq_ulps(&other.0, 4)
502    }
503}
504
505/// A line cap.
506///
507/// `stroke-linecap` attribute in the SVG.
508#[allow(missing_docs)]
509#[derive(Clone, Copy, PartialEq, Debug)]
510pub enum LineCap {
511    Butt,
512    Round,
513    Square,
514}
515
516impl Default for LineCap {
517    fn default() -> Self {
518        Self::Butt
519    }
520}
521
522/// A line join.
523///
524/// `stroke-linejoin` attribute in the SVG.
525#[allow(missing_docs)]
526#[derive(Clone, Copy, PartialEq, Debug)]
527pub enum LineJoin {
528    Miter,
529    MiterClip,
530    Round,
531    Bevel,
532}
533
534impl Default for LineJoin {
535    fn default() -> Self {
536        Self::Miter
537    }
538}
539
540/// A stroke style.
541#[derive(Clone, Debug)]
542pub struct Stroke {
543    pub(crate) paint: Paint,
544    pub(crate) dasharray: Option<Vec<f32>>,
545    pub(crate) dashoffset: f32,
546    pub(crate) miterlimit: StrokeMiterlimit,
547    pub(crate) opacity: Opacity,
548    pub(crate) width: StrokeWidth,
549    pub(crate) linecap: LineCap,
550    pub(crate) linejoin: LineJoin,
551    // Whether the current stroke needs to be resolved relative
552    // to a context element.
553    pub(crate) context_element: Option<ContextElement>,
554}
555
556impl Stroke {
557    /// Stroke paint.
558    pub fn paint(&self) -> &Paint {
559        &self.paint
560    }
561
562    /// Stroke dash array.
563    pub fn dasharray(&self) -> Option<&[f32]> {
564        self.dasharray.as_deref()
565    }
566
567    /// Stroke dash offset.
568    pub fn dashoffset(&self) -> f32 {
569        self.dashoffset
570    }
571
572    /// Stroke miter limit.
573    pub fn miterlimit(&self) -> StrokeMiterlimit {
574        self.miterlimit
575    }
576
577    /// Stroke opacity.
578    pub fn opacity(&self) -> Opacity {
579        self.opacity
580    }
581
582    /// Stroke width.
583    pub fn width(&self) -> StrokeWidth {
584        self.width
585    }
586
587    /// Stroke linecap.
588    pub fn linecap(&self) -> LineCap {
589        self.linecap
590    }
591
592    /// Stroke linejoin.
593    pub fn linejoin(&self) -> LineJoin {
594        self.linejoin
595    }
596
597    /// Converts into a `tiny_skia_path::Stroke` type.
598    pub fn to_tiny_skia(&self) -> tiny_skia_path::Stroke {
599        let mut stroke = tiny_skia_path::Stroke {
600            width: self.width.get(),
601            miter_limit: self.miterlimit.get(),
602            line_cap: match self.linecap {
603                LineCap::Butt => tiny_skia_path::LineCap::Butt,
604                LineCap::Round => tiny_skia_path::LineCap::Round,
605                LineCap::Square => tiny_skia_path::LineCap::Square,
606            },
607            line_join: match self.linejoin {
608                LineJoin::Miter => tiny_skia_path::LineJoin::Miter,
609                LineJoin::MiterClip => tiny_skia_path::LineJoin::MiterClip,
610                LineJoin::Round => tiny_skia_path::LineJoin::Round,
611                LineJoin::Bevel => tiny_skia_path::LineJoin::Bevel,
612            },
613            // According to the spec, dash should not be accounted during
614            // bbox calculation.
615            dash: None,
616        };
617
618        if let Some(ref list) = self.dasharray {
619            stroke.dash = tiny_skia_path::StrokeDash::new(list.clone(), self.dashoffset);
620        }
621
622        stroke
623    }
624}
625
626/// A fill rule.
627///
628/// `fill-rule` attribute in the SVG.
629#[allow(missing_docs)]
630#[derive(Clone, Copy, PartialEq, Debug)]
631pub enum FillRule {
632    NonZero,
633    EvenOdd,
634}
635
636impl Default for FillRule {
637    fn default() -> Self {
638        Self::NonZero
639    }
640}
641
642#[derive(Clone, Copy, Debug)]
643pub(crate) enum ContextElement {
644    /// The current context element is a use node. Since we can get
645    /// the bounding box of a use node only once we have converted
646    /// all elements, we need to fix the transform and units of
647    /// the stroke/fill after converting the whole tree.
648    UseNode,
649    /// The current context element is a path node (i.e. only applicable
650    /// if we draw the marker of a path). Since we already know the bounding
651    /// box of the path when rendering the markers, we can convert them directly,
652    /// so we do it while parsing.
653    PathNode(Transform, Option<NonZeroRect>),
654}
655
656/// A fill style.
657#[derive(Clone, Debug)]
658pub struct Fill {
659    pub(crate) paint: Paint,
660    pub(crate) opacity: Opacity,
661    pub(crate) rule: FillRule,
662    // Whether the current fill needs to be resolved relative
663    // to a context element.
664    pub(crate) context_element: Option<ContextElement>,
665}
666
667impl Fill {
668    /// Fill paint.
669    pub fn paint(&self) -> &Paint {
670        &self.paint
671    }
672
673    /// Fill opacity.
674    pub fn opacity(&self) -> Opacity {
675        self.opacity
676    }
677
678    /// Fill rule.
679    pub fn rule(&self) -> FillRule {
680        self.rule
681    }
682}
683
684impl Default for Fill {
685    fn default() -> Self {
686        Fill {
687            paint: Paint::Color(Color::black()),
688            opacity: Opacity::ONE,
689            rule: FillRule::default(),
690            context_element: None,
691        }
692    }
693}
694
695/// A 8-bit RGB color.
696#[derive(Clone, Copy, PartialEq, Debug)]
697#[allow(missing_docs)]
698pub struct Color {
699    pub red: u8,
700    pub green: u8,
701    pub blue: u8,
702}
703
704impl Color {
705    /// Constructs a new `Color` from RGB values.
706    #[inline]
707    pub fn new_rgb(red: u8, green: u8, blue: u8) -> Color {
708        Color { red, green, blue }
709    }
710
711    /// Constructs a new `Color` set to black.
712    #[inline]
713    pub fn black() -> Color {
714        Color::new_rgb(0, 0, 0)
715    }
716
717    /// Constructs a new `Color` set to white.
718    #[inline]
719    pub fn white() -> Color {
720        Color::new_rgb(255, 255, 255)
721    }
722}
723
724/// A paint style.
725///
726/// `paint` value type in the SVG.
727#[allow(missing_docs)]
728#[derive(Clone, Debug)]
729pub enum Paint {
730    Color(Color),
731    LinearGradient(Arc<LinearGradient>),
732    RadialGradient(Arc<RadialGradient>),
733    Pattern(Arc<Pattern>),
734}
735
736impl PartialEq for Paint {
737    #[inline]
738    fn eq(&self, other: &Self) -> bool {
739        match (self, other) {
740            (Self::Color(lc), Self::Color(rc)) => lc == rc,
741            (Self::LinearGradient(ref lg1), Self::LinearGradient(ref lg2)) => Arc::ptr_eq(lg1, lg2),
742            (Self::RadialGradient(ref rg1), Self::RadialGradient(ref rg2)) => Arc::ptr_eq(rg1, rg2),
743            (Self::Pattern(ref p1), Self::Pattern(ref p2)) => Arc::ptr_eq(p1, p2),
744            _ => false,
745        }
746    }
747}
748
749/// A clip-path element.
750///
751/// `clipPath` element in SVG.
752#[derive(Debug)]
753pub struct ClipPath {
754    pub(crate) id: NonEmptyString,
755    pub(crate) transform: Transform,
756    pub(crate) clip_path: Option<Arc<ClipPath>>,
757    pub(crate) root: Group,
758}
759
760impl ClipPath {
761    pub(crate) fn empty(id: NonEmptyString) -> Self {
762        ClipPath {
763            id,
764            transform: Transform::default(),
765            clip_path: None,
766            root: Group::empty(),
767        }
768    }
769
770    /// Element's ID.
771    ///
772    /// Taken from the SVG itself.
773    /// Used only during SVG writing. `resvg` doesn't rely on this property.
774    pub fn id(&self) -> &str {
775        self.id.get()
776    }
777
778    /// Clip path transform.
779    ///
780    /// `transform` in SVG.
781    pub fn transform(&self) -> Transform {
782        self.transform
783    }
784
785    /// Additional clip path.
786    ///
787    /// `clip-path` in SVG.
788    pub fn clip_path(&self) -> Option<&ClipPath> {
789        self.clip_path.as_deref()
790    }
791
792    /// Clip path children.
793    pub fn root(&self) -> &Group {
794        &self.root
795    }
796}
797
798/// A mask type.
799#[derive(Clone, Copy, PartialEq, Debug)]
800pub enum MaskType {
801    /// Indicates that the luminance values of the mask should be used.
802    Luminance,
803    /// Indicates that the alpha values of the mask should be used.
804    Alpha,
805}
806
807impl Default for MaskType {
808    fn default() -> Self {
809        Self::Luminance
810    }
811}
812
813/// A mask element.
814///
815/// `mask` element in SVG.
816#[derive(Debug)]
817pub struct Mask {
818    pub(crate) id: NonEmptyString,
819    pub(crate) rect: NonZeroRect,
820    pub(crate) kind: MaskType,
821    pub(crate) mask: Option<Arc<Mask>>,
822    pub(crate) root: Group,
823}
824
825impl Mask {
826    /// Element's ID.
827    ///
828    /// Taken from the SVG itself.
829    /// Used only during SVG writing. `resvg` doesn't rely on this property.
830    pub fn id(&self) -> &str {
831        self.id.get()
832    }
833
834    /// Mask rectangle.
835    ///
836    /// `x`, `y`, `width` and `height` in SVG.
837    pub fn rect(&self) -> NonZeroRect {
838        self.rect
839    }
840
841    /// Mask type.
842    ///
843    /// `mask-type` in SVG.
844    pub fn kind(&self) -> MaskType {
845        self.kind
846    }
847
848    /// Additional mask.
849    ///
850    /// `mask` in SVG.
851    pub fn mask(&self) -> Option<&Mask> {
852        self.mask.as_deref()
853    }
854
855    /// Mask children.
856    ///
857    /// A mask can have no children, in which case the whole element should be masked out.
858    pub fn root(&self) -> &Group {
859        &self.root
860    }
861}
862
863/// Node's kind.
864#[allow(missing_docs)]
865#[derive(Clone, Debug)]
866pub enum Node {
867    Group(Box<Group>),
868    Path(Box<Path>),
869    Image(Box<Image>),
870    Text(Box<Text>),
871}
872
873impl Node {
874    /// Returns node's ID.
875    pub fn id(&self) -> &str {
876        match self {
877            Node::Group(ref e) => e.id.as_str(),
878            Node::Path(ref e) => e.id.as_str(),
879            Node::Image(ref e) => e.id.as_str(),
880            Node::Text(ref e) => e.id.as_str(),
881        }
882    }
883
884    /// Returns node's absolute transform.
885    ///
886    /// This method is cheap since absolute transforms are already resolved.
887    pub fn abs_transform(&self) -> Transform {
888        match self {
889            Node::Group(ref group) => group.abs_transform(),
890            Node::Path(ref path) => path.abs_transform(),
891            Node::Image(ref image) => image.abs_transform(),
892            Node::Text(ref text) => text.abs_transform(),
893        }
894    }
895
896    /// Returns node's bounding box in object coordinates, if any.
897    pub fn bounding_box(&self) -> Rect {
898        match self {
899            Node::Group(ref group) => group.bounding_box(),
900            Node::Path(ref path) => path.bounding_box(),
901            Node::Image(ref image) => image.bounding_box(),
902            Node::Text(ref text) => text.bounding_box(),
903        }
904    }
905
906    /// Returns node's bounding box in canvas coordinates, if any.
907    pub fn abs_bounding_box(&self) -> Rect {
908        match self {
909            Node::Group(ref group) => group.abs_bounding_box(),
910            Node::Path(ref path) => path.abs_bounding_box(),
911            Node::Image(ref image) => image.abs_bounding_box(),
912            Node::Text(ref text) => text.abs_bounding_box(),
913        }
914    }
915
916    /// Returns node's bounding box, including stroke, in object coordinates, if any.
917    pub fn stroke_bounding_box(&self) -> Rect {
918        match self {
919            Node::Group(ref group) => group.stroke_bounding_box(),
920            Node::Path(ref path) => path.stroke_bounding_box(),
921            // Image cannot be stroked.
922            Node::Image(ref image) => image.bounding_box(),
923            Node::Text(ref text) => text.stroke_bounding_box(),
924        }
925    }
926
927    /// Returns node's bounding box, including stroke, in canvas coordinates, if any.
928    pub fn abs_stroke_bounding_box(&self) -> Rect {
929        match self {
930            Node::Group(ref group) => group.abs_stroke_bounding_box(),
931            Node::Path(ref path) => path.abs_stroke_bounding_box(),
932            // Image cannot be stroked.
933            Node::Image(ref image) => image.abs_bounding_box(),
934            Node::Text(ref text) => text.abs_stroke_bounding_box(),
935        }
936    }
937
938    /// Element's "layer" bounding box in canvas units, if any.
939    ///
940    /// For most nodes this is just `abs_bounding_box`,
941    /// but for groups this is `abs_layer_bounding_box`.
942    ///
943    /// See [`Group::layer_bounding_box`] for details.
944    pub fn abs_layer_bounding_box(&self) -> Option<NonZeroRect> {
945        match self {
946            Node::Group(ref group) => Some(group.abs_layer_bounding_box()),
947            // Hor/ver path without stroke can return None. This is expected.
948            Node::Path(ref path) => path.abs_bounding_box().to_non_zero_rect(),
949            Node::Image(ref image) => image.abs_bounding_box().to_non_zero_rect(),
950            Node::Text(ref text) => text.abs_bounding_box().to_non_zero_rect(),
951        }
952    }
953
954    /// Calls a closure for each subroot this `Node` has.
955    ///
956    /// The [`Tree::root`](Tree::root) field contain only render-able SVG elements.
957    /// But some elements, specifically clip paths, masks, patterns and feImage
958    /// can store their own SVG subtrees.
959    /// And while one can access them manually, it's pretty verbose.
960    /// This methods allows looping over _all_ SVG elements present in the `Tree`.
961    ///
962    /// # Example
963    ///
964    /// ```no_run
965    /// fn all_nodes(parent: &usvg::Group) {
966    ///     for node in parent.children() {
967    ///         // do stuff...
968    ///
969    ///         if let usvg::Node::Group(ref g) = node {
970    ///             all_nodes(g);
971    ///         }
972    ///
973    ///         // handle subroots as well
974    ///         node.subroots(|subroot| all_nodes(subroot));
975    ///     }
976    /// }
977    /// ```
978    pub fn subroots<F: FnMut(&Group)>(&self, mut f: F) {
979        match self {
980            Node::Group(ref group) => group.subroots(&mut f),
981            Node::Path(ref path) => path.subroots(&mut f),
982            Node::Image(ref image) => image.subroots(&mut f),
983            Node::Text(ref text) => text.subroots(&mut f),
984        }
985    }
986}
987
988/// A group container.
989///
990/// The preprocessor will remove all groups that don't impact rendering.
991/// Those that left is just an indicator that a new canvas should be created.
992///
993/// `g` element in SVG.
994#[derive(Clone, Debug)]
995pub struct Group {
996    pub(crate) id: String,
997    pub(crate) transform: Transform,
998    pub(crate) abs_transform: Transform,
999    pub(crate) opacity: Opacity,
1000    pub(crate) blend_mode: BlendMode,
1001    pub(crate) isolate: bool,
1002    pub(crate) clip_path: Option<Arc<ClipPath>>,
1003    /// Whether the group is a context element (i.e. a use node)
1004    pub(crate) is_context_element: bool,
1005    pub(crate) mask: Option<Arc<Mask>>,
1006    pub(crate) filters: Vec<Arc<filter::Filter>>,
1007    pub(crate) bounding_box: Rect,
1008    pub(crate) abs_bounding_box: Rect,
1009    pub(crate) stroke_bounding_box: Rect,
1010    pub(crate) abs_stroke_bounding_box: Rect,
1011    pub(crate) layer_bounding_box: NonZeroRect,
1012    pub(crate) abs_layer_bounding_box: NonZeroRect,
1013    pub(crate) children: Vec<Node>,
1014}
1015
1016impl Group {
1017    pub(crate) fn empty() -> Self {
1018        let dummy = Rect::from_xywh(0.0, 0.0, 0.0, 0.0).unwrap();
1019        Group {
1020            id: String::new(),
1021            transform: Transform::default(),
1022            abs_transform: Transform::default(),
1023            opacity: Opacity::ONE,
1024            blend_mode: BlendMode::Normal,
1025            isolate: false,
1026            clip_path: None,
1027            mask: None,
1028            filters: Vec::new(),
1029            is_context_element: false,
1030            bounding_box: dummy,
1031            abs_bounding_box: dummy,
1032            stroke_bounding_box: dummy,
1033            abs_stroke_bounding_box: dummy,
1034            layer_bounding_box: NonZeroRect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap(),
1035            abs_layer_bounding_box: NonZeroRect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap(),
1036            children: Vec::new(),
1037        }
1038    }
1039
1040    /// Element's ID.
1041    ///
1042    /// Taken from the SVG itself.
1043    /// Isn't automatically generated.
1044    /// Can be empty.
1045    pub fn id(&self) -> &str {
1046        &self.id
1047    }
1048
1049    /// Element's transform.
1050    ///
1051    /// This is a relative transform. The one that is set via the `transform` attribute in SVG.
1052    pub fn transform(&self) -> Transform {
1053        self.transform
1054    }
1055
1056    /// Element's absolute transform.
1057    ///
1058    /// Contains all ancestors transforms including group's transform.
1059    ///
1060    /// Note that subroots, like clipPaths, masks and patterns, have their own root transform,
1061    /// which isn't affected by the node that references this subroot.
1062    pub fn abs_transform(&self) -> Transform {
1063        self.abs_transform
1064    }
1065
1066    /// Group opacity.
1067    ///
1068    /// After the group is rendered we should combine
1069    /// it with a parent group using the specified opacity.
1070    pub fn opacity(&self) -> Opacity {
1071        self.opacity
1072    }
1073
1074    /// Group blend mode.
1075    ///
1076    /// `mix-blend-mode` in SVG.
1077    pub fn blend_mode(&self) -> BlendMode {
1078        self.blend_mode
1079    }
1080
1081    /// Group isolation.
1082    ///
1083    /// `isolation` in SVG.
1084    pub fn isolate(&self) -> bool {
1085        self.isolate
1086    }
1087
1088    /// Element's clip path.
1089    pub fn clip_path(&self) -> Option<&ClipPath> {
1090        self.clip_path.as_deref()
1091    }
1092
1093    /// Element's mask.
1094    pub fn mask(&self) -> Option<&Mask> {
1095        self.mask.as_deref()
1096    }
1097
1098    /// Element's filters.
1099    pub fn filters(&self) -> &[Arc<filter::Filter>] {
1100        &self.filters
1101    }
1102
1103    /// Element's object bounding box.
1104    ///
1105    /// `objectBoundingBox` in SVG terms. Meaning it doesn't affected by parent transforms.
1106    ///
1107    /// Can be set to `None` in case of an empty group.
1108    pub fn bounding_box(&self) -> Rect {
1109        self.bounding_box
1110    }
1111
1112    /// Element's bounding box in canvas coordinates.
1113    ///
1114    /// `userSpaceOnUse` in SVG terms.
1115    pub fn abs_bounding_box(&self) -> Rect {
1116        self.abs_bounding_box
1117    }
1118
1119    /// Element's object bounding box including stroke.
1120    ///
1121    /// Similar to `bounding_box`, but includes stroke.
1122    pub fn stroke_bounding_box(&self) -> Rect {
1123        self.stroke_bounding_box
1124    }
1125
1126    /// Element's bounding box including stroke in user coordinates.
1127    ///
1128    /// Similar to `abs_bounding_box`, but includes stroke.
1129    pub fn abs_stroke_bounding_box(&self) -> Rect {
1130        self.abs_stroke_bounding_box
1131    }
1132
1133    /// Element's "layer" bounding box in object units.
1134    ///
1135    /// Conceptually, this is `stroke_bounding_box` expanded and/or clipped
1136    /// by `filters_bounding_box`, but also including all the children.
1137    /// This is the bounding box `resvg` will later use to allocate layers/pixmaps
1138    /// during isolated groups rendering.
1139    ///
1140    /// Only groups have it, because only groups can have filters.
1141    /// For other nodes layer bounding box is the same as stroke bounding box.
1142    ///
1143    /// Unlike other bounding boxes, cannot have zero size.
1144    ///
1145    /// Returns 0x0x1x1 for empty groups.
1146    pub fn layer_bounding_box(&self) -> NonZeroRect {
1147        self.layer_bounding_box
1148    }
1149
1150    /// Element's "layer" bounding box in canvas units.
1151    pub fn abs_layer_bounding_box(&self) -> NonZeroRect {
1152        self.abs_layer_bounding_box
1153    }
1154
1155    /// Group's children.
1156    pub fn children(&self) -> &[Node] {
1157        &self.children
1158    }
1159
1160    /// Checks if this group should be isolated during rendering.
1161    pub fn should_isolate(&self) -> bool {
1162        self.isolate
1163            || self.opacity != Opacity::ONE
1164            || self.clip_path.is_some()
1165            || self.mask.is_some()
1166            || !self.filters.is_empty()
1167            || self.blend_mode != BlendMode::Normal // TODO: probably not needed?
1168    }
1169
1170    /// Returns `true` if the group has any children.
1171    pub fn has_children(&self) -> bool {
1172        !self.children.is_empty()
1173    }
1174
1175    /// Calculates a node's filter bounding box.
1176    ///
1177    /// Filters with `objectBoundingBox` and missing or zero `bounding_box` would be ignored.
1178    ///
1179    /// Note that a filter region can act like a clipping rectangle,
1180    /// therefore this function can produce a bounding box smaller than `bounding_box`.
1181    ///
1182    /// Returns `None` when then group has no filters.
1183    ///
1184    /// This function is very fast, that's why we do not store this bbox as a `Group` field.
1185    pub fn filters_bounding_box(&self) -> Option<NonZeroRect> {
1186        let mut full_region = BBox::default();
1187        for filter in &self.filters {
1188            full_region = full_region.expand(filter.rect);
1189        }
1190
1191        full_region.to_non_zero_rect()
1192    }
1193
1194    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1195        if let Some(ref clip) = self.clip_path {
1196            f(&clip.root);
1197
1198            if let Some(ref sub_clip) = clip.clip_path {
1199                f(&sub_clip.root);
1200            }
1201        }
1202
1203        if let Some(ref mask) = self.mask {
1204            f(&mask.root);
1205
1206            if let Some(ref sub_mask) = mask.mask {
1207                f(&sub_mask.root);
1208            }
1209        }
1210
1211        for filter in &self.filters {
1212            for primitive in &filter.primitives {
1213                if let filter::Kind::Image(ref image) = primitive.kind {
1214                    f(image.root());
1215                }
1216            }
1217        }
1218    }
1219}
1220
1221/// Representation of the [`paint-order`] property.
1222///
1223/// `usvg` will handle `markers` automatically,
1224/// therefore we provide only `fill` and `stroke` variants.
1225///
1226/// [`paint-order`]: https://www.w3.org/TR/SVG2/painting.html#PaintOrder
1227#[derive(Clone, Copy, PartialEq, Debug)]
1228#[allow(missing_docs)]
1229pub enum PaintOrder {
1230    FillAndStroke,
1231    StrokeAndFill,
1232}
1233
1234impl Default for PaintOrder {
1235    fn default() -> Self {
1236        Self::FillAndStroke
1237    }
1238}
1239
1240/// A path element.
1241#[derive(Clone, Debug)]
1242pub struct Path {
1243    pub(crate) id: String,
1244    pub(crate) visible: bool,
1245    pub(crate) fill: Option<Fill>,
1246    pub(crate) stroke: Option<Stroke>,
1247    pub(crate) paint_order: PaintOrder,
1248    pub(crate) rendering_mode: ShapeRendering,
1249    pub(crate) data: Arc<tiny_skia_path::Path>,
1250    pub(crate) abs_transform: Transform,
1251    pub(crate) bounding_box: Rect,
1252    pub(crate) abs_bounding_box: Rect,
1253    pub(crate) stroke_bounding_box: Rect,
1254    pub(crate) abs_stroke_bounding_box: Rect,
1255}
1256
1257impl Path {
1258    pub(crate) fn new_simple(data: Arc<tiny_skia_path::Path>) -> Option<Self> {
1259        Self::new(
1260            String::new(),
1261            true,
1262            None,
1263            None,
1264            PaintOrder::default(),
1265            ShapeRendering::default(),
1266            data,
1267            Transform::default(),
1268        )
1269    }
1270
1271    pub(crate) fn new(
1272        id: String,
1273        visible: bool,
1274        fill: Option<Fill>,
1275        stroke: Option<Stroke>,
1276        paint_order: PaintOrder,
1277        rendering_mode: ShapeRendering,
1278        data: Arc<tiny_skia_path::Path>,
1279        abs_transform: Transform,
1280    ) -> Option<Self> {
1281        let bounding_box = data.compute_tight_bounds()?;
1282        let stroke_bounding_box =
1283            Path::calculate_stroke_bbox(stroke.as_ref(), &data).unwrap_or(bounding_box);
1284
1285        let abs_bounding_box: Rect;
1286        let abs_stroke_bounding_box: Rect;
1287        if abs_transform.has_skew() {
1288            // TODO: avoid re-alloc
1289            let path2 = data.as_ref().clone();
1290            let path2 = path2.transform(abs_transform)?;
1291            abs_bounding_box = path2.compute_tight_bounds()?;
1292            abs_stroke_bounding_box =
1293                Path::calculate_stroke_bbox(stroke.as_ref(), &path2).unwrap_or(abs_bounding_box);
1294        } else {
1295            // A transform without a skew can be performed just on a bbox.
1296            abs_bounding_box = bounding_box.transform(abs_transform)?;
1297            abs_stroke_bounding_box = stroke_bounding_box.transform(abs_transform)?;
1298        }
1299
1300        Some(Path {
1301            id,
1302            visible,
1303            fill,
1304            stroke,
1305            paint_order,
1306            rendering_mode,
1307            data,
1308            abs_transform,
1309            bounding_box,
1310            abs_bounding_box,
1311            stroke_bounding_box,
1312            abs_stroke_bounding_box,
1313        })
1314    }
1315
1316    /// Element's ID.
1317    ///
1318    /// Taken from the SVG itself.
1319    /// Isn't automatically generated.
1320    /// Can be empty.
1321    pub fn id(&self) -> &str {
1322        &self.id
1323    }
1324
1325    /// Element visibility.
1326    pub fn is_visible(&self) -> bool {
1327        self.visible
1328    }
1329
1330    /// Fill style.
1331    pub fn fill(&self) -> Option<&Fill> {
1332        self.fill.as_ref()
1333    }
1334
1335    /// Stroke style.
1336    pub fn stroke(&self) -> Option<&Stroke> {
1337        self.stroke.as_ref()
1338    }
1339
1340    /// Fill and stroke paint order.
1341    ///
1342    /// Since markers will be replaced with regular nodes automatically,
1343    /// `usvg` doesn't provide the `markers` order type. It's was already done.
1344    ///
1345    /// `paint-order` in SVG.
1346    pub fn paint_order(&self) -> PaintOrder {
1347        self.paint_order
1348    }
1349
1350    /// Rendering mode.
1351    ///
1352    /// `shape-rendering` in SVG.
1353    pub fn rendering_mode(&self) -> ShapeRendering {
1354        self.rendering_mode
1355    }
1356
1357    // TODO: find a better name
1358    /// Segments list.
1359    ///
1360    /// All segments are in absolute coordinates.
1361    pub fn data(&self) -> &tiny_skia_path::Path {
1362        self.data.as_ref()
1363    }
1364
1365    /// Element's absolute transform.
1366    ///
1367    /// Contains all ancestors transforms including elements's transform.
1368    ///
1369    /// Note that this is not the relative transform present in SVG.
1370    /// The SVG one would be set only on groups.
1371    pub fn abs_transform(&self) -> Transform {
1372        self.abs_transform
1373    }
1374
1375    /// Element's object bounding box.
1376    ///
1377    /// `objectBoundingBox` in SVG terms. Meaning it doesn't affected by parent transforms.
1378    pub fn bounding_box(&self) -> Rect {
1379        self.bounding_box
1380    }
1381
1382    /// Element's bounding box in canvas coordinates.
1383    ///
1384    /// `userSpaceOnUse` in SVG terms.
1385    pub fn abs_bounding_box(&self) -> Rect {
1386        self.abs_bounding_box
1387    }
1388
1389    /// Element's object bounding box including stroke.
1390    ///
1391    /// Will have the same value as `bounding_box` when path has no stroke.
1392    pub fn stroke_bounding_box(&self) -> Rect {
1393        self.stroke_bounding_box
1394    }
1395
1396    /// Element's bounding box including stroke in canvas coordinates.
1397    ///
1398    /// Will have the same value as `abs_bounding_box` when path has no stroke.
1399    pub fn abs_stroke_bounding_box(&self) -> Rect {
1400        self.abs_stroke_bounding_box
1401    }
1402
1403    fn calculate_stroke_bbox(stroke: Option<&Stroke>, path: &tiny_skia_path::Path) -> Option<Rect> {
1404        let mut stroke = stroke?.to_tiny_skia();
1405        // According to the spec, dash should not be accounted during bbox calculation.
1406        stroke.dash = None;
1407
1408        // TODO: avoid for round and bevel caps
1409
1410        // Expensive, but there is not much we can do about it.
1411        if let Some(stroked_path) = path.stroke(&stroke, 1.0) {
1412            return stroked_path.compute_tight_bounds();
1413        }
1414
1415        None
1416    }
1417
1418    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1419        if let Some(Paint::Pattern(ref patt)) = self.fill.as_ref().map(|f| &f.paint) {
1420            f(patt.root())
1421        }
1422        if let Some(Paint::Pattern(ref patt)) = self.stroke.as_ref().map(|f| &f.paint) {
1423            f(patt.root())
1424        }
1425    }
1426}
1427
1428/// An embedded image kind.
1429#[derive(Clone)]
1430pub enum ImageKind {
1431    /// A reference to raw JPEG data. Should be decoded by the caller.
1432    JPEG(Arc<Vec<u8>>),
1433    /// A reference to raw PNG data. Should be decoded by the caller.
1434    PNG(Arc<Vec<u8>>),
1435    /// A reference to raw GIF data. Should be decoded by the caller.
1436    GIF(Arc<Vec<u8>>),
1437    /// A reference to raw WebP data. Should be decoded by the caller.
1438    WEBP(Arc<Vec<u8>>),
1439    /// A preprocessed SVG tree. Can be rendered as is.
1440    SVG(Tree),
1441}
1442
1443impl ImageKind {
1444    pub(crate) fn actual_size(&self) -> Option<Size> {
1445        match self {
1446            ImageKind::JPEG(ref data)
1447            | ImageKind::PNG(ref data)
1448            | ImageKind::GIF(ref data)
1449            | ImageKind::WEBP(ref data) => imagesize::blob_size(data)
1450                .ok()
1451                .and_then(|size| Size::from_wh(size.width as f32, size.height as f32))
1452                .log_none(|| log::warn!("Image has an invalid size. Skipped.")),
1453            ImageKind::SVG(ref svg) => Some(svg.size),
1454        }
1455    }
1456}
1457
1458impl std::fmt::Debug for ImageKind {
1459    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1460        match self {
1461            ImageKind::JPEG(_) => f.write_str("ImageKind::JPEG(..)"),
1462            ImageKind::PNG(_) => f.write_str("ImageKind::PNG(..)"),
1463            ImageKind::GIF(_) => f.write_str("ImageKind::GIF(..)"),
1464            ImageKind::WEBP(_) => f.write_str("ImageKind::WEBP(..)"),
1465            ImageKind::SVG(_) => f.write_str("ImageKind::SVG(..)"),
1466        }
1467    }
1468}
1469
1470/// A raster image element.
1471///
1472/// `image` element in SVG.
1473#[derive(Clone, Debug)]
1474pub struct Image {
1475    pub(crate) id: String,
1476    pub(crate) visible: bool,
1477    pub(crate) size: Size,
1478    pub(crate) rendering_mode: ImageRendering,
1479    pub(crate) kind: ImageKind,
1480    pub(crate) abs_transform: Transform,
1481    pub(crate) abs_bounding_box: NonZeroRect,
1482}
1483
1484impl Image {
1485    /// Element's ID.
1486    ///
1487    /// Taken from the SVG itself.
1488    /// Isn't automatically generated.
1489    /// Can be empty.
1490    pub fn id(&self) -> &str {
1491        &self.id
1492    }
1493
1494    /// Element visibility.
1495    pub fn is_visible(&self) -> bool {
1496        self.visible
1497    }
1498
1499    /// The actual image size.
1500    ///
1501    /// This is not `width` and `height` attributes,
1502    /// but rather the actual PNG/JPEG/GIF/SVG image size.
1503    pub fn size(&self) -> Size {
1504        self.size
1505    }
1506
1507    /// Rendering mode.
1508    ///
1509    /// `image-rendering` in SVG.
1510    pub fn rendering_mode(&self) -> ImageRendering {
1511        self.rendering_mode
1512    }
1513
1514    /// Image data.
1515    pub fn kind(&self) -> &ImageKind {
1516        &self.kind
1517    }
1518
1519    /// Element's absolute transform.
1520    ///
1521    /// Contains all ancestors transforms including elements's transform.
1522    ///
1523    /// Note that this is not the relative transform present in SVG.
1524    /// The SVG one would be set only on groups.
1525    pub fn abs_transform(&self) -> Transform {
1526        self.abs_transform
1527    }
1528
1529    /// Element's object bounding box.
1530    ///
1531    /// `objectBoundingBox` in SVG terms. Meaning it doesn't affected by parent transforms.
1532    pub fn bounding_box(&self) -> Rect {
1533        self.size.to_rect(0.0, 0.0).unwrap()
1534    }
1535
1536    /// Element's bounding box in canvas coordinates.
1537    ///
1538    /// `userSpaceOnUse` in SVG terms.
1539    pub fn abs_bounding_box(&self) -> Rect {
1540        self.abs_bounding_box.to_rect()
1541    }
1542
1543    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1544        if let ImageKind::SVG(ref tree) = self.kind {
1545            f(&tree.root)
1546        }
1547    }
1548}
1549
1550/// A nodes tree container.
1551#[allow(missing_debug_implementations)]
1552#[derive(Clone, Debug)]
1553pub struct Tree {
1554    pub(crate) size: Size,
1555    pub(crate) root: Group,
1556    pub(crate) linear_gradients: Vec<Arc<LinearGradient>>,
1557    pub(crate) radial_gradients: Vec<Arc<RadialGradient>>,
1558    pub(crate) patterns: Vec<Arc<Pattern>>,
1559    pub(crate) clip_paths: Vec<Arc<ClipPath>>,
1560    pub(crate) masks: Vec<Arc<Mask>>,
1561    pub(crate) filters: Vec<Arc<filter::Filter>>,
1562    #[cfg(feature = "text")]
1563    pub(crate) fontdb: Arc<fontdb::Database>,
1564}
1565
1566impl Tree {
1567    /// Image size.
1568    ///
1569    /// Size of an image that should be created to fit the SVG.
1570    ///
1571    /// `width` and `height` in SVG.
1572    pub fn size(&self) -> Size {
1573        self.size
1574    }
1575
1576    /// The root element of the SVG tree.
1577    pub fn root(&self) -> &Group {
1578        &self.root
1579    }
1580
1581    /// Returns a renderable node by ID.
1582    ///
1583    /// If an empty ID is provided, than this method will always return `None`.
1584    pub fn node_by_id(&self, id: &str) -> Option<&Node> {
1585        if id.is_empty() {
1586            return None;
1587        }
1588
1589        node_by_id(&self.root, id)
1590    }
1591
1592    /// Checks if the current tree has any text nodes.
1593    pub fn has_text_nodes(&self) -> bool {
1594        has_text_nodes(&self.root)
1595    }
1596
1597    /// Returns a list of all unique [`LinearGradient`]s in the tree.
1598    pub fn linear_gradients(&self) -> &[Arc<LinearGradient>] {
1599        &self.linear_gradients
1600    }
1601
1602    /// Returns a list of all unique [`RadialGradient`]s in the tree.
1603    pub fn radial_gradients(&self) -> &[Arc<RadialGradient>] {
1604        &self.radial_gradients
1605    }
1606
1607    /// Returns a list of all unique [`Pattern`]s in the tree.
1608    pub fn patterns(&self) -> &[Arc<Pattern>] {
1609        &self.patterns
1610    }
1611
1612    /// Returns a list of all unique [`ClipPath`]s in the tree.
1613    pub fn clip_paths(&self) -> &[Arc<ClipPath>] {
1614        &self.clip_paths
1615    }
1616
1617    /// Returns a list of all unique [`Mask`]s in the tree.
1618    pub fn masks(&self) -> &[Arc<Mask>] {
1619        &self.masks
1620    }
1621
1622    /// Returns a list of all unique [`Filter`](filter::Filter)s in the tree.
1623    pub fn filters(&self) -> &[Arc<filter::Filter>] {
1624        &self.filters
1625    }
1626
1627    /// Returns the font database that applies to all text nodes in the tree.
1628    #[cfg(feature = "text")]
1629    pub fn fontdb(&self) -> &Arc<fontdb::Database> {
1630        &self.fontdb
1631    }
1632
1633    pub(crate) fn collect_paint_servers(&mut self) {
1634        loop_over_paint_servers(&self.root, &mut |paint| match paint {
1635            Paint::Color(_) => {}
1636            Paint::LinearGradient(lg) => {
1637                if !self
1638                    .linear_gradients
1639                    .iter()
1640                    .any(|other| Arc::ptr_eq(lg, other))
1641                {
1642                    self.linear_gradients.push(lg.clone());
1643                }
1644            }
1645            Paint::RadialGradient(rg) => {
1646                if !self
1647                    .radial_gradients
1648                    .iter()
1649                    .any(|other| Arc::ptr_eq(rg, other))
1650                {
1651                    self.radial_gradients.push(rg.clone());
1652                }
1653            }
1654            Paint::Pattern(patt) => {
1655                if !self.patterns.iter().any(|other| Arc::ptr_eq(patt, other)) {
1656                    self.patterns.push(patt.clone());
1657                }
1658            }
1659        });
1660    }
1661}
1662
1663fn node_by_id<'a>(parent: &'a Group, id: &str) -> Option<&'a Node> {
1664    for child in &parent.children {
1665        if child.id() == id {
1666            return Some(child);
1667        }
1668
1669        if let Node::Group(ref g) = child {
1670            if let Some(n) = node_by_id(g, id) {
1671                return Some(n);
1672            }
1673        }
1674    }
1675
1676    None
1677}
1678
1679fn has_text_nodes(root: &Group) -> bool {
1680    for node in &root.children {
1681        if let Node::Text(_) = node {
1682            return true;
1683        }
1684
1685        let mut has_text = false;
1686
1687        if let Node::Image(ref image) = node {
1688            if let ImageKind::SVG(ref tree) = image.kind {
1689                if has_text_nodes(&tree.root) {
1690                    has_text = true;
1691                }
1692            }
1693        }
1694
1695        node.subroots(|subroot| has_text |= has_text_nodes(subroot));
1696
1697        if has_text {
1698            return true;
1699        }
1700    }
1701
1702    true
1703}
1704
1705fn loop_over_paint_servers(parent: &Group, f: &mut dyn FnMut(&Paint)) {
1706    fn push(paint: Option<&Paint>, f: &mut dyn FnMut(&Paint)) {
1707        if let Some(paint) = paint {
1708            f(paint);
1709        }
1710    }
1711
1712    for node in &parent.children {
1713        match node {
1714            Node::Group(ref group) => loop_over_paint_servers(group, f),
1715            Node::Path(ref path) => {
1716                push(path.fill.as_ref().map(|f| &f.paint), f);
1717                push(path.stroke.as_ref().map(|f| &f.paint), f);
1718            }
1719            Node::Image(_) => {}
1720            // Flattened text would be used instead.
1721            Node::Text(_) => {}
1722        }
1723
1724        node.subroots(|subroot| loop_over_paint_servers(subroot, f));
1725    }
1726}
1727
1728impl Group {
1729    pub(crate) fn collect_clip_paths(&self, clip_paths: &mut Vec<Arc<ClipPath>>) {
1730        for node in self.children() {
1731            if let Node::Group(ref g) = node {
1732                if let Some(ref clip) = g.clip_path {
1733                    if !clip_paths.iter().any(|other| Arc::ptr_eq(clip, other)) {
1734                        clip_paths.push(clip.clone());
1735                    }
1736
1737                    if let Some(ref sub_clip) = clip.clip_path {
1738                        if !clip_paths.iter().any(|other| Arc::ptr_eq(sub_clip, other)) {
1739                            clip_paths.push(sub_clip.clone());
1740                        }
1741                    }
1742                }
1743            }
1744
1745            node.subroots(|subroot| subroot.collect_clip_paths(clip_paths));
1746
1747            if let Node::Group(ref g) = node {
1748                g.collect_clip_paths(clip_paths);
1749            }
1750        }
1751    }
1752
1753    pub(crate) fn collect_masks(&self, masks: &mut Vec<Arc<Mask>>) {
1754        for node in self.children() {
1755            if let Node::Group(ref g) = node {
1756                if let Some(ref mask) = g.mask {
1757                    if !masks.iter().any(|other| Arc::ptr_eq(mask, other)) {
1758                        masks.push(mask.clone());
1759                    }
1760
1761                    if let Some(ref sub_mask) = mask.mask {
1762                        if !masks.iter().any(|other| Arc::ptr_eq(sub_mask, other)) {
1763                            masks.push(sub_mask.clone());
1764                        }
1765                    }
1766                }
1767            }
1768
1769            node.subroots(|subroot| subroot.collect_masks(masks));
1770
1771            if let Node::Group(ref g) = node {
1772                g.collect_masks(masks);
1773            }
1774        }
1775    }
1776
1777    pub(crate) fn collect_filters(&self, filters: &mut Vec<Arc<filter::Filter>>) {
1778        for node in self.children() {
1779            if let Node::Group(ref g) = node {
1780                for filter in g.filters() {
1781                    if !filters.iter().any(|other| Arc::ptr_eq(filter, other)) {
1782                        filters.push(filter.clone());
1783                    }
1784                }
1785            }
1786
1787            node.subroots(|subroot| subroot.collect_filters(filters));
1788
1789            if let Node::Group(ref g) = node {
1790                g.collect_filters(filters);
1791            }
1792        }
1793    }
1794
1795    pub(crate) fn calculate_object_bbox(&mut self) -> Option<NonZeroRect> {
1796        let mut bbox = BBox::default();
1797        for child in &self.children {
1798            let mut c_bbox = child.bounding_box();
1799            if let Node::Group(ref group) = child {
1800                if let Some(r) = c_bbox.transform(group.transform) {
1801                    c_bbox = r;
1802                }
1803            }
1804
1805            bbox = bbox.expand(c_bbox);
1806        }
1807
1808        bbox.to_non_zero_rect()
1809    }
1810
1811    pub(crate) fn calculate_bounding_boxes(&mut self) -> Option<()> {
1812        let mut bbox = BBox::default();
1813        let mut abs_bbox = BBox::default();
1814        let mut stroke_bbox = BBox::default();
1815        let mut abs_stroke_bbox = BBox::default();
1816        let mut layer_bbox = BBox::default();
1817        for child in &self.children {
1818            {
1819                let mut c_bbox = child.bounding_box();
1820                if let Node::Group(ref group) = child {
1821                    if let Some(r) = c_bbox.transform(group.transform) {
1822                        c_bbox = r;
1823                    }
1824                }
1825
1826                bbox = bbox.expand(c_bbox);
1827            }
1828
1829            abs_bbox = abs_bbox.expand(child.abs_bounding_box());
1830
1831            {
1832                let mut c_bbox = child.stroke_bounding_box();
1833                if let Node::Group(ref group) = child {
1834                    if let Some(r) = c_bbox.transform(group.transform) {
1835                        c_bbox = r;
1836                    }
1837                }
1838
1839                stroke_bbox = stroke_bbox.expand(c_bbox);
1840            }
1841
1842            abs_stroke_bbox = abs_stroke_bbox.expand(child.abs_stroke_bounding_box());
1843
1844            if let Node::Group(ref group) = child {
1845                let r = group.layer_bounding_box;
1846                if let Some(r) = r.transform(group.transform) {
1847                    layer_bbox = layer_bbox.expand(r);
1848                }
1849            } else {
1850                // Not a group - no need to transform.
1851                layer_bbox = layer_bbox.expand(child.stroke_bounding_box());
1852            }
1853        }
1854
1855        // `bbox` can be None for empty groups, but we still have to
1856        // calculate `layer_bounding_box after` it.
1857        if let Some(bbox) = bbox.to_rect() {
1858            self.bounding_box = bbox;
1859            self.abs_bounding_box = abs_bbox.to_rect()?;
1860            self.stroke_bounding_box = stroke_bbox.to_rect()?;
1861            self.abs_stroke_bounding_box = abs_stroke_bbox.to_rect()?;
1862        }
1863
1864        // Filter bbox has a higher priority than layers bbox.
1865        if let Some(filter_bbox) = self.filters_bounding_box() {
1866            self.layer_bounding_box = filter_bbox;
1867        } else {
1868            self.layer_bounding_box = layer_bbox.to_non_zero_rect()?;
1869        }
1870
1871        self.abs_layer_bounding_box = self.layer_bounding_box.transform(self.abs_transform)?;
1872
1873        Some(())
1874    }
1875}