usvg/tree/
mod.rs

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