Skip to main content

usvg/tree/
mod.rs

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