Skip to main content

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