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