Skip to main content

deft_usvg/tree/
mod.rs

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