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