1pub mod filter;
5mod geom;
6mod text;
7
8use std::sync::Arc;
9
10pub use strict_num::{self, ApproxEqUlps, NonZeroPositiveF32, NormalizedF32, PositiveF32};
11
12pub use tiny_skia_path;
13
14pub use self::geom::*;
15pub use self::text::*;
16
17use crate::OptionLog;
18
19pub type Opacity = NormalizedF32;
21
22#[derive(Debug)]
24pub(crate) struct NonEmptyString(String);
25
26impl NonEmptyString {
27    pub(crate) fn new(string: String) -> Option<Self> {
28        if string.trim().is_empty() {
29            return None;
30        }
31
32        Some(NonEmptyString(string))
33    }
34
35    pub(crate) fn get(&self) -> &str {
36        &self.0
37    }
38
39    pub(crate) fn take(self) -> String {
40        self.0
41    }
42}
43
44#[derive(Clone, Copy, Debug)]
48pub struct NonZeroF32(f32);
49
50impl NonZeroF32 {
51    #[inline]
53    pub fn new(n: f32) -> Option<Self> {
54        if n.approx_eq_ulps(&0.0, 4) {
55            None
56        } else {
57            Some(NonZeroF32(n))
58        }
59    }
60
61    #[inline]
63    pub fn get(&self) -> f32 {
64        self.0
65    }
66}
67
68#[derive(Clone, Copy, PartialEq, Debug)]
69pub(crate) enum Units {
70    UserSpaceOnUse,
71    ObjectBoundingBox,
72}
73
74#[allow(missing_docs)]
80#[derive(Clone, Copy, PartialEq, Debug)]
81pub(crate) enum Visibility {
82    Visible,
83    Hidden,
84    Collapse,
85}
86
87impl Default for Visibility {
88    fn default() -> Self {
89        Self::Visible
90    }
91}
92
93#[derive(Clone, Copy, PartialEq, Debug)]
97#[allow(missing_docs)]
98pub enum ShapeRendering {
99    OptimizeSpeed,
100    CrispEdges,
101    GeometricPrecision,
102}
103
104impl ShapeRendering {
105    pub fn use_shape_antialiasing(self) -> bool {
107        match self {
108            ShapeRendering::OptimizeSpeed => false,
109            ShapeRendering::CrispEdges => false,
110            ShapeRendering::GeometricPrecision => true,
111        }
112    }
113}
114
115impl Default for ShapeRendering {
116    fn default() -> Self {
117        Self::GeometricPrecision
118    }
119}
120
121impl std::str::FromStr for ShapeRendering {
122    type Err = &'static str;
123
124    fn from_str(s: &str) -> Result<Self, Self::Err> {
125        match s {
126            "optimizeSpeed" => Ok(ShapeRendering::OptimizeSpeed),
127            "crispEdges" => Ok(ShapeRendering::CrispEdges),
128            "geometricPrecision" => Ok(ShapeRendering::GeometricPrecision),
129            _ => Err("invalid"),
130        }
131    }
132}
133
134#[allow(missing_docs)]
138#[derive(Clone, Copy, PartialEq, Debug)]
139pub enum TextRendering {
140    OptimizeSpeed,
141    OptimizeLegibility,
142    GeometricPrecision,
143}
144
145impl Default for TextRendering {
146    fn default() -> Self {
147        Self::OptimizeLegibility
148    }
149}
150
151impl std::str::FromStr for TextRendering {
152    type Err = &'static str;
153
154    fn from_str(s: &str) -> Result<Self, Self::Err> {
155        match s {
156            "optimizeSpeed" => Ok(TextRendering::OptimizeSpeed),
157            "optimizeLegibility" => Ok(TextRendering::OptimizeLegibility),
158            "geometricPrecision" => Ok(TextRendering::GeometricPrecision),
159            _ => Err("invalid"),
160        }
161    }
162}
163
164#[allow(missing_docs)]
168#[derive(Clone, Copy, PartialEq, Debug)]
169pub enum ImageRendering {
170    OptimizeQuality,
171    OptimizeSpeed,
172    Smooth,
174    HighQuality,
175    CrispEdges,
176    Pixelated,
177}
178
179impl Default for ImageRendering {
180    fn default() -> Self {
181        Self::OptimizeQuality
182    }
183}
184
185impl std::str::FromStr for ImageRendering {
186    type Err = &'static str;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        match s {
190            "optimizeQuality" => Ok(ImageRendering::OptimizeQuality),
191            "optimizeSpeed" => Ok(ImageRendering::OptimizeSpeed),
192            "smooth" => Ok(ImageRendering::Smooth),
193            "high-quality" => Ok(ImageRendering::HighQuality),
194            "crisp-edges" => Ok(ImageRendering::CrispEdges),
195            "pixelated" => Ok(ImageRendering::Pixelated),
196            _ => Err("invalid"),
197        }
198    }
199}
200
201#[allow(missing_docs)]
205#[derive(Clone, Copy, PartialEq, Debug)]
206pub enum BlendMode {
207    Normal,
208    Multiply,
209    Screen,
210    Overlay,
211    Darken,
212    Lighten,
213    ColorDodge,
214    ColorBurn,
215    HardLight,
216    SoftLight,
217    Difference,
218    Exclusion,
219    Hue,
220    Saturation,
221    Color,
222    Luminosity,
223}
224
225impl Default for BlendMode {
226    fn default() -> Self {
227        Self::Normal
228    }
229}
230
231#[allow(missing_docs)]
235#[derive(Clone, Copy, PartialEq, Debug)]
236pub enum SpreadMethod {
237    Pad,
238    Reflect,
239    Repeat,
240}
241
242impl Default for SpreadMethod {
243    fn default() -> Self {
244        Self::Pad
245    }
246}
247
248#[derive(Debug)]
250pub struct BaseGradient {
251    pub(crate) id: NonEmptyString,
252    pub(crate) units: Units, pub(crate) transform: Transform,
254    pub(crate) spread_method: SpreadMethod,
255    pub(crate) stops: Vec<Stop>,
256}
257
258impl BaseGradient {
259    pub fn id(&self) -> &str {
264        self.id.get()
265    }
266
267    pub fn transform(&self) -> Transform {
271        self.transform
272    }
273
274    pub fn spread_method(&self) -> SpreadMethod {
278        self.spread_method
279    }
280
281    pub fn stops(&self) -> &[Stop] {
283        &self.stops
284    }
285}
286
287#[derive(Debug)]
291pub struct LinearGradient {
292    pub(crate) base: BaseGradient,
293    pub(crate) x1: f32,
294    pub(crate) y1: f32,
295    pub(crate) x2: f32,
296    pub(crate) y2: f32,
297}
298
299impl LinearGradient {
300    pub fn x1(&self) -> f32 {
302        self.x1
303    }
304
305    pub fn y1(&self) -> f32 {
307        self.y1
308    }
309
310    pub fn x2(&self) -> f32 {
312        self.x2
313    }
314
315    pub fn y2(&self) -> f32 {
317        self.y2
318    }
319}
320
321impl std::ops::Deref for LinearGradient {
322    type Target = BaseGradient;
323
324    fn deref(&self) -> &Self::Target {
325        &self.base
326    }
327}
328
329#[derive(Debug)]
333pub struct RadialGradient {
334    pub(crate) base: BaseGradient,
335    pub(crate) cx: f32,
336    pub(crate) cy: f32,
337    pub(crate) r: PositiveF32,
338    pub(crate) fx: f32,
339    pub(crate) fy: f32,
340}
341
342impl RadialGradient {
343    pub fn cx(&self) -> f32 {
345        self.cx
346    }
347
348    pub fn cy(&self) -> f32 {
350        self.cy
351    }
352
353    pub fn r(&self) -> PositiveF32 {
355        self.r
356    }
357
358    pub fn fx(&self) -> f32 {
360        self.fx
361    }
362
363    pub fn fy(&self) -> f32 {
365        self.fy
366    }
367}
368
369impl std::ops::Deref for RadialGradient {
370    type Target = BaseGradient;
371
372    fn deref(&self) -> &Self::Target {
373        &self.base
374    }
375}
376
377pub type StopOffset = NormalizedF32;
379
380#[derive(Clone, Copy, Debug)]
384pub struct Stop {
385    pub(crate) offset: StopOffset,
386    pub(crate) color: Color,
387    pub(crate) opacity: Opacity,
388}
389
390impl Stop {
391    pub fn offset(&self) -> StopOffset {
395        self.offset
396    }
397
398    pub fn color(&self) -> Color {
402        self.color
403    }
404
405    pub fn opacity(&self) -> Opacity {
409        self.opacity
410    }
411}
412
413#[derive(Debug)]
417pub struct Pattern {
418    pub(crate) id: NonEmptyString,
419    pub(crate) units: Units,         pub(crate) content_units: Units, pub(crate) transform: Transform,
422    pub(crate) rect: NonZeroRect,
423    pub(crate) view_box: Option<ViewBox>,
424    pub(crate) root: Group,
425}
426
427impl Pattern {
428    pub fn id(&self) -> &str {
433        self.id.get()
434    }
435
436    pub fn transform(&self) -> Transform {
440        self.transform
441    }
442
443    pub fn rect(&self) -> NonZeroRect {
447        self.rect
448    }
449
450    pub fn root(&self) -> &Group {
452        &self.root
453    }
454}
455
456pub type StrokeWidth = NonZeroPositiveF32;
458
459#[derive(Clone, Copy, Debug)]
463pub struct StrokeMiterlimit(f32);
464
465impl StrokeMiterlimit {
466    #[inline]
468    pub fn new(n: f32) -> Self {
469        debug_assert!(n.is_finite());
470        debug_assert!(n >= 1.0);
471
472        let n = if !(n >= 1.0) { 1.0 } else { n };
473
474        StrokeMiterlimit(n)
475    }
476
477    #[inline]
479    pub fn get(&self) -> f32 {
480        self.0
481    }
482}
483
484impl Default for StrokeMiterlimit {
485    #[inline]
486    fn default() -> Self {
487        StrokeMiterlimit::new(4.0)
488    }
489}
490
491impl From<f32> for StrokeMiterlimit {
492    #[inline]
493    fn from(n: f32) -> Self {
494        Self::new(n)
495    }
496}
497
498impl PartialEq for StrokeMiterlimit {
499    #[inline]
500    fn eq(&self, other: &Self) -> bool {
501        self.0.approx_eq_ulps(&other.0, 4)
502    }
503}
504
505#[allow(missing_docs)]
509#[derive(Clone, Copy, PartialEq, Debug)]
510pub enum LineCap {
511    Butt,
512    Round,
513    Square,
514}
515
516impl Default for LineCap {
517    fn default() -> Self {
518        Self::Butt
519    }
520}
521
522#[allow(missing_docs)]
526#[derive(Clone, Copy, PartialEq, Debug)]
527pub enum LineJoin {
528    Miter,
529    MiterClip,
530    Round,
531    Bevel,
532}
533
534impl Default for LineJoin {
535    fn default() -> Self {
536        Self::Miter
537    }
538}
539
540#[derive(Clone, Debug)]
542pub struct Stroke {
543    pub(crate) paint: Paint,
544    pub(crate) dasharray: Option<Vec<f32>>,
545    pub(crate) dashoffset: f32,
546    pub(crate) miterlimit: StrokeMiterlimit,
547    pub(crate) opacity: Opacity,
548    pub(crate) width: StrokeWidth,
549    pub(crate) linecap: LineCap,
550    pub(crate) linejoin: LineJoin,
551    pub(crate) context_element: Option<ContextElement>,
554}
555
556impl Stroke {
557    pub fn paint(&self) -> &Paint {
559        &self.paint
560    }
561
562    pub fn dasharray(&self) -> Option<&[f32]> {
564        self.dasharray.as_deref()
565    }
566
567    pub fn dashoffset(&self) -> f32 {
569        self.dashoffset
570    }
571
572    pub fn miterlimit(&self) -> StrokeMiterlimit {
574        self.miterlimit
575    }
576
577    pub fn opacity(&self) -> Opacity {
579        self.opacity
580    }
581
582    pub fn width(&self) -> StrokeWidth {
584        self.width
585    }
586
587    pub fn linecap(&self) -> LineCap {
589        self.linecap
590    }
591
592    pub fn linejoin(&self) -> LineJoin {
594        self.linejoin
595    }
596
597    pub fn to_tiny_skia(&self) -> tiny_skia_path::Stroke {
599        let mut stroke = tiny_skia_path::Stroke {
600            width: self.width.get(),
601            miter_limit: self.miterlimit.get(),
602            line_cap: match self.linecap {
603                LineCap::Butt => tiny_skia_path::LineCap::Butt,
604                LineCap::Round => tiny_skia_path::LineCap::Round,
605                LineCap::Square => tiny_skia_path::LineCap::Square,
606            },
607            line_join: match self.linejoin {
608                LineJoin::Miter => tiny_skia_path::LineJoin::Miter,
609                LineJoin::MiterClip => tiny_skia_path::LineJoin::MiterClip,
610                LineJoin::Round => tiny_skia_path::LineJoin::Round,
611                LineJoin::Bevel => tiny_skia_path::LineJoin::Bevel,
612            },
613            dash: None,
616        };
617
618        if let Some(ref list) = self.dasharray {
619            stroke.dash = tiny_skia_path::StrokeDash::new(list.clone(), self.dashoffset);
620        }
621
622        stroke
623    }
624}
625
626#[allow(missing_docs)]
630#[derive(Clone, Copy, PartialEq, Debug)]
631pub enum FillRule {
632    NonZero,
633    EvenOdd,
634}
635
636impl Default for FillRule {
637    fn default() -> Self {
638        Self::NonZero
639    }
640}
641
642#[derive(Clone, Copy, Debug)]
643pub(crate) enum ContextElement {
644    UseNode,
649    PathNode(Transform, Option<NonZeroRect>),
654}
655
656#[derive(Clone, Debug)]
658pub struct Fill {
659    pub(crate) paint: Paint,
660    pub(crate) opacity: Opacity,
661    pub(crate) rule: FillRule,
662    pub(crate) context_element: Option<ContextElement>,
665}
666
667impl Fill {
668    pub fn paint(&self) -> &Paint {
670        &self.paint
671    }
672
673    pub fn opacity(&self) -> Opacity {
675        self.opacity
676    }
677
678    pub fn rule(&self) -> FillRule {
680        self.rule
681    }
682}
683
684impl Default for Fill {
685    fn default() -> Self {
686        Fill {
687            paint: Paint::Color(Color::black()),
688            opacity: Opacity::ONE,
689            rule: FillRule::default(),
690            context_element: None,
691        }
692    }
693}
694
695#[derive(Clone, Copy, PartialEq, Debug)]
697#[allow(missing_docs)]
698pub struct Color {
699    pub red: u8,
700    pub green: u8,
701    pub blue: u8,
702}
703
704impl Color {
705    #[inline]
707    pub fn new_rgb(red: u8, green: u8, blue: u8) -> Color {
708        Color { red, green, blue }
709    }
710
711    #[inline]
713    pub fn black() -> Color {
714        Color::new_rgb(0, 0, 0)
715    }
716
717    #[inline]
719    pub fn white() -> Color {
720        Color::new_rgb(255, 255, 255)
721    }
722}
723
724#[allow(missing_docs)]
728#[derive(Clone, Debug)]
729pub enum Paint {
730    Color(Color),
731    LinearGradient(Arc<LinearGradient>),
732    RadialGradient(Arc<RadialGradient>),
733    Pattern(Arc<Pattern>),
734}
735
736impl PartialEq for Paint {
737    #[inline]
738    fn eq(&self, other: &Self) -> bool {
739        match (self, other) {
740            (Self::Color(lc), Self::Color(rc)) => lc == rc,
741            (Self::LinearGradient(ref lg1), Self::LinearGradient(ref lg2)) => Arc::ptr_eq(lg1, lg2),
742            (Self::RadialGradient(ref rg1), Self::RadialGradient(ref rg2)) => Arc::ptr_eq(rg1, rg2),
743            (Self::Pattern(ref p1), Self::Pattern(ref p2)) => Arc::ptr_eq(p1, p2),
744            _ => false,
745        }
746    }
747}
748
749#[derive(Debug)]
753pub struct ClipPath {
754    pub(crate) id: NonEmptyString,
755    pub(crate) transform: Transform,
756    pub(crate) clip_path: Option<Arc<ClipPath>>,
757    pub(crate) root: Group,
758}
759
760impl ClipPath {
761    pub(crate) fn empty(id: NonEmptyString) -> Self {
762        ClipPath {
763            id,
764            transform: Transform::default(),
765            clip_path: None,
766            root: Group::empty(),
767        }
768    }
769
770    pub fn id(&self) -> &str {
775        self.id.get()
776    }
777
778    pub fn transform(&self) -> Transform {
782        self.transform
783    }
784
785    pub fn clip_path(&self) -> Option<&ClipPath> {
789        self.clip_path.as_deref()
790    }
791
792    pub fn root(&self) -> &Group {
794        &self.root
795    }
796}
797
798#[derive(Clone, Copy, PartialEq, Debug)]
800pub enum MaskType {
801    Luminance,
803    Alpha,
805}
806
807impl Default for MaskType {
808    fn default() -> Self {
809        Self::Luminance
810    }
811}
812
813#[derive(Debug)]
817pub struct Mask {
818    pub(crate) id: NonEmptyString,
819    pub(crate) rect: NonZeroRect,
820    pub(crate) kind: MaskType,
821    pub(crate) mask: Option<Arc<Mask>>,
822    pub(crate) root: Group,
823}
824
825impl Mask {
826    pub fn id(&self) -> &str {
831        self.id.get()
832    }
833
834    pub fn rect(&self) -> NonZeroRect {
838        self.rect
839    }
840
841    pub fn kind(&self) -> MaskType {
845        self.kind
846    }
847
848    pub fn mask(&self) -> Option<&Mask> {
852        self.mask.as_deref()
853    }
854
855    pub fn root(&self) -> &Group {
859        &self.root
860    }
861}
862
863#[allow(missing_docs)]
865#[derive(Clone, Debug)]
866pub enum Node {
867    Group(Box<Group>),
868    Path(Box<Path>),
869    Image(Box<Image>),
870    Text(Box<Text>),
871}
872
873impl Node {
874    pub fn id(&self) -> &str {
876        match self {
877            Node::Group(ref e) => e.id.as_str(),
878            Node::Path(ref e) => e.id.as_str(),
879            Node::Image(ref e) => e.id.as_str(),
880            Node::Text(ref e) => e.id.as_str(),
881        }
882    }
883
884    pub fn abs_transform(&self) -> Transform {
888        match self {
889            Node::Group(ref group) => group.abs_transform(),
890            Node::Path(ref path) => path.abs_transform(),
891            Node::Image(ref image) => image.abs_transform(),
892            Node::Text(ref text) => text.abs_transform(),
893        }
894    }
895
896    pub fn bounding_box(&self) -> Rect {
898        match self {
899            Node::Group(ref group) => group.bounding_box(),
900            Node::Path(ref path) => path.bounding_box(),
901            Node::Image(ref image) => image.bounding_box(),
902            Node::Text(ref text) => text.bounding_box(),
903        }
904    }
905
906    pub fn abs_bounding_box(&self) -> Rect {
908        match self {
909            Node::Group(ref group) => group.abs_bounding_box(),
910            Node::Path(ref path) => path.abs_bounding_box(),
911            Node::Image(ref image) => image.abs_bounding_box(),
912            Node::Text(ref text) => text.abs_bounding_box(),
913        }
914    }
915
916    pub fn stroke_bounding_box(&self) -> Rect {
918        match self {
919            Node::Group(ref group) => group.stroke_bounding_box(),
920            Node::Path(ref path) => path.stroke_bounding_box(),
921            Node::Image(ref image) => image.bounding_box(),
923            Node::Text(ref text) => text.stroke_bounding_box(),
924        }
925    }
926
927    pub fn abs_stroke_bounding_box(&self) -> Rect {
929        match self {
930            Node::Group(ref group) => group.abs_stroke_bounding_box(),
931            Node::Path(ref path) => path.abs_stroke_bounding_box(),
932            Node::Image(ref image) => image.abs_bounding_box(),
934            Node::Text(ref text) => text.abs_stroke_bounding_box(),
935        }
936    }
937
938    pub fn abs_layer_bounding_box(&self) -> Option<NonZeroRect> {
945        match self {
946            Node::Group(ref group) => Some(group.abs_layer_bounding_box()),
947            Node::Path(ref path) => path.abs_bounding_box().to_non_zero_rect(),
949            Node::Image(ref image) => image.abs_bounding_box().to_non_zero_rect(),
950            Node::Text(ref text) => text.abs_bounding_box().to_non_zero_rect(),
951        }
952    }
953
954    pub fn subroots<F: FnMut(&Group)>(&self, mut f: F) {
979        match self {
980            Node::Group(ref group) => group.subroots(&mut f),
981            Node::Path(ref path) => path.subroots(&mut f),
982            Node::Image(ref image) => image.subroots(&mut f),
983            Node::Text(ref text) => text.subroots(&mut f),
984        }
985    }
986}
987
988#[derive(Clone, Debug)]
995pub struct Group {
996    pub(crate) id: String,
997    pub(crate) transform: Transform,
998    pub(crate) abs_transform: Transform,
999    pub(crate) opacity: Opacity,
1000    pub(crate) blend_mode: BlendMode,
1001    pub(crate) isolate: bool,
1002    pub(crate) clip_path: Option<Arc<ClipPath>>,
1003    pub(crate) is_context_element: bool,
1005    pub(crate) mask: Option<Arc<Mask>>,
1006    pub(crate) filters: Vec<Arc<filter::Filter>>,
1007    pub(crate) bounding_box: Rect,
1008    pub(crate) abs_bounding_box: Rect,
1009    pub(crate) stroke_bounding_box: Rect,
1010    pub(crate) abs_stroke_bounding_box: Rect,
1011    pub(crate) layer_bounding_box: NonZeroRect,
1012    pub(crate) abs_layer_bounding_box: NonZeroRect,
1013    pub(crate) children: Vec<Node>,
1014}
1015
1016impl Group {
1017    pub(crate) fn empty() -> Self {
1018        let dummy = Rect::from_xywh(0.0, 0.0, 0.0, 0.0).unwrap();
1019        Group {
1020            id: String::new(),
1021            transform: Transform::default(),
1022            abs_transform: Transform::default(),
1023            opacity: Opacity::ONE,
1024            blend_mode: BlendMode::Normal,
1025            isolate: false,
1026            clip_path: None,
1027            mask: None,
1028            filters: Vec::new(),
1029            is_context_element: false,
1030            bounding_box: dummy,
1031            abs_bounding_box: dummy,
1032            stroke_bounding_box: dummy,
1033            abs_stroke_bounding_box: dummy,
1034            layer_bounding_box: NonZeroRect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap(),
1035            abs_layer_bounding_box: NonZeroRect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap(),
1036            children: Vec::new(),
1037        }
1038    }
1039
1040    pub fn id(&self) -> &str {
1046        &self.id
1047    }
1048
1049    pub fn transform(&self) -> Transform {
1053        self.transform
1054    }
1055
1056    pub fn abs_transform(&self) -> Transform {
1063        self.abs_transform
1064    }
1065
1066    pub fn opacity(&self) -> Opacity {
1071        self.opacity
1072    }
1073
1074    pub fn blend_mode(&self) -> BlendMode {
1078        self.blend_mode
1079    }
1080
1081    pub fn isolate(&self) -> bool {
1085        self.isolate
1086    }
1087
1088    pub fn clip_path(&self) -> Option<&ClipPath> {
1090        self.clip_path.as_deref()
1091    }
1092
1093    pub fn mask(&self) -> Option<&Mask> {
1095        self.mask.as_deref()
1096    }
1097
1098    pub fn filters(&self) -> &[Arc<filter::Filter>] {
1100        &self.filters
1101    }
1102
1103    pub fn bounding_box(&self) -> Rect {
1109        self.bounding_box
1110    }
1111
1112    pub fn abs_bounding_box(&self) -> Rect {
1116        self.abs_bounding_box
1117    }
1118
1119    pub fn stroke_bounding_box(&self) -> Rect {
1123        self.stroke_bounding_box
1124    }
1125
1126    pub fn abs_stroke_bounding_box(&self) -> Rect {
1130        self.abs_stroke_bounding_box
1131    }
1132
1133    pub fn layer_bounding_box(&self) -> NonZeroRect {
1147        self.layer_bounding_box
1148    }
1149
1150    pub fn abs_layer_bounding_box(&self) -> NonZeroRect {
1152        self.abs_layer_bounding_box
1153    }
1154
1155    pub fn children(&self) -> &[Node] {
1157        &self.children
1158    }
1159
1160    pub fn should_isolate(&self) -> bool {
1162        self.isolate
1163            || self.opacity != Opacity::ONE
1164            || self.clip_path.is_some()
1165            || self.mask.is_some()
1166            || !self.filters.is_empty()
1167            || self.blend_mode != BlendMode::Normal }
1169
1170    pub fn has_children(&self) -> bool {
1172        !self.children.is_empty()
1173    }
1174
1175    pub fn filters_bounding_box(&self) -> Option<NonZeroRect> {
1186        let mut full_region = BBox::default();
1187        for filter in &self.filters {
1188            full_region = full_region.expand(filter.rect);
1189        }
1190
1191        full_region.to_non_zero_rect()
1192    }
1193
1194    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1195        if let Some(ref clip) = self.clip_path {
1196            f(&clip.root);
1197
1198            if let Some(ref sub_clip) = clip.clip_path {
1199                f(&sub_clip.root);
1200            }
1201        }
1202
1203        if let Some(ref mask) = self.mask {
1204            f(&mask.root);
1205
1206            if let Some(ref sub_mask) = mask.mask {
1207                f(&sub_mask.root);
1208            }
1209        }
1210
1211        for filter in &self.filters {
1212            for primitive in &filter.primitives {
1213                if let filter::Kind::Image(ref image) = primitive.kind {
1214                    f(image.root());
1215                }
1216            }
1217        }
1218    }
1219}
1220
1221#[derive(Clone, Copy, PartialEq, Debug)]
1228#[allow(missing_docs)]
1229pub enum PaintOrder {
1230    FillAndStroke,
1231    StrokeAndFill,
1232}
1233
1234impl Default for PaintOrder {
1235    fn default() -> Self {
1236        Self::FillAndStroke
1237    }
1238}
1239
1240#[derive(Clone, Debug)]
1242pub struct Path {
1243    pub(crate) id: String,
1244    pub(crate) visible: bool,
1245    pub(crate) fill: Option<Fill>,
1246    pub(crate) stroke: Option<Stroke>,
1247    pub(crate) paint_order: PaintOrder,
1248    pub(crate) rendering_mode: ShapeRendering,
1249    pub(crate) data: Arc<tiny_skia_path::Path>,
1250    pub(crate) abs_transform: Transform,
1251    pub(crate) bounding_box: Rect,
1252    pub(crate) abs_bounding_box: Rect,
1253    pub(crate) stroke_bounding_box: Rect,
1254    pub(crate) abs_stroke_bounding_box: Rect,
1255}
1256
1257impl Path {
1258    pub(crate) fn new_simple(data: Arc<tiny_skia_path::Path>) -> Option<Self> {
1259        Self::new(
1260            String::new(),
1261            true,
1262            None,
1263            None,
1264            PaintOrder::default(),
1265            ShapeRendering::default(),
1266            data,
1267            Transform::default(),
1268        )
1269    }
1270
1271    pub(crate) fn new(
1272        id: String,
1273        visible: bool,
1274        fill: Option<Fill>,
1275        stroke: Option<Stroke>,
1276        paint_order: PaintOrder,
1277        rendering_mode: ShapeRendering,
1278        data: Arc<tiny_skia_path::Path>,
1279        abs_transform: Transform,
1280    ) -> Option<Self> {
1281        let bounding_box = data.compute_tight_bounds()?;
1282        let stroke_bounding_box =
1283            Path::calculate_stroke_bbox(stroke.as_ref(), &data).unwrap_or(bounding_box);
1284
1285        let abs_bounding_box: Rect;
1286        let abs_stroke_bounding_box: Rect;
1287        if abs_transform.has_skew() {
1288            let path2 = data.as_ref().clone();
1290            let path2 = path2.transform(abs_transform)?;
1291            abs_bounding_box = path2.compute_tight_bounds()?;
1292            abs_stroke_bounding_box =
1293                Path::calculate_stroke_bbox(stroke.as_ref(), &path2).unwrap_or(abs_bounding_box);
1294        } else {
1295            abs_bounding_box = bounding_box.transform(abs_transform)?;
1297            abs_stroke_bounding_box = stroke_bounding_box.transform(abs_transform)?;
1298        }
1299
1300        Some(Path {
1301            id,
1302            visible,
1303            fill,
1304            stroke,
1305            paint_order,
1306            rendering_mode,
1307            data,
1308            abs_transform,
1309            bounding_box,
1310            abs_bounding_box,
1311            stroke_bounding_box,
1312            abs_stroke_bounding_box,
1313        })
1314    }
1315
1316    pub fn id(&self) -> &str {
1322        &self.id
1323    }
1324
1325    pub fn is_visible(&self) -> bool {
1327        self.visible
1328    }
1329
1330    pub fn fill(&self) -> Option<&Fill> {
1332        self.fill.as_ref()
1333    }
1334
1335    pub fn stroke(&self) -> Option<&Stroke> {
1337        self.stroke.as_ref()
1338    }
1339
1340    pub fn paint_order(&self) -> PaintOrder {
1347        self.paint_order
1348    }
1349
1350    pub fn rendering_mode(&self) -> ShapeRendering {
1354        self.rendering_mode
1355    }
1356
1357    pub fn data(&self) -> &tiny_skia_path::Path {
1362        self.data.as_ref()
1363    }
1364
1365    pub fn abs_transform(&self) -> Transform {
1372        self.abs_transform
1373    }
1374
1375    pub fn bounding_box(&self) -> Rect {
1379        self.bounding_box
1380    }
1381
1382    pub fn abs_bounding_box(&self) -> Rect {
1386        self.abs_bounding_box
1387    }
1388
1389    pub fn stroke_bounding_box(&self) -> Rect {
1393        self.stroke_bounding_box
1394    }
1395
1396    pub fn abs_stroke_bounding_box(&self) -> Rect {
1400        self.abs_stroke_bounding_box
1401    }
1402
1403    fn calculate_stroke_bbox(stroke: Option<&Stroke>, path: &tiny_skia_path::Path) -> Option<Rect> {
1404        let mut stroke = stroke?.to_tiny_skia();
1405        stroke.dash = None;
1407
1408        if let Some(stroked_path) = path.stroke(&stroke, 1.0) {
1412            return stroked_path.compute_tight_bounds();
1413        }
1414
1415        None
1416    }
1417
1418    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1419        if let Some(Paint::Pattern(ref patt)) = self.fill.as_ref().map(|f| &f.paint) {
1420            f(patt.root())
1421        }
1422        if let Some(Paint::Pattern(ref patt)) = self.stroke.as_ref().map(|f| &f.paint) {
1423            f(patt.root())
1424        }
1425    }
1426}
1427
1428#[derive(Clone)]
1430pub enum ImageKind {
1431    JPEG(Arc<Vec<u8>>),
1433    PNG(Arc<Vec<u8>>),
1435    GIF(Arc<Vec<u8>>),
1437    WEBP(Arc<Vec<u8>>),
1439    SVG(Tree),
1441}
1442
1443impl ImageKind {
1444    pub(crate) fn actual_size(&self) -> Option<Size> {
1445        match self {
1446            ImageKind::JPEG(ref data)
1447            | ImageKind::PNG(ref data)
1448            | ImageKind::GIF(ref data)
1449            | ImageKind::WEBP(ref data) => imagesize::blob_size(data)
1450                .ok()
1451                .and_then(|size| Size::from_wh(size.width as f32, size.height as f32))
1452                .log_none(|| log::warn!("Image has an invalid size. Skipped.")),
1453            ImageKind::SVG(ref svg) => Some(svg.size),
1454        }
1455    }
1456}
1457
1458impl std::fmt::Debug for ImageKind {
1459    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1460        match self {
1461            ImageKind::JPEG(_) => f.write_str("ImageKind::JPEG(..)"),
1462            ImageKind::PNG(_) => f.write_str("ImageKind::PNG(..)"),
1463            ImageKind::GIF(_) => f.write_str("ImageKind::GIF(..)"),
1464            ImageKind::WEBP(_) => f.write_str("ImageKind::WEBP(..)"),
1465            ImageKind::SVG(_) => f.write_str("ImageKind::SVG(..)"),
1466        }
1467    }
1468}
1469
1470#[derive(Clone, Debug)]
1474pub struct Image {
1475    pub(crate) id: String,
1476    pub(crate) visible: bool,
1477    pub(crate) size: Size,
1478    pub(crate) rendering_mode: ImageRendering,
1479    pub(crate) kind: ImageKind,
1480    pub(crate) abs_transform: Transform,
1481    pub(crate) abs_bounding_box: NonZeroRect,
1482}
1483
1484impl Image {
1485    pub fn id(&self) -> &str {
1491        &self.id
1492    }
1493
1494    pub fn is_visible(&self) -> bool {
1496        self.visible
1497    }
1498
1499    pub fn size(&self) -> Size {
1504        self.size
1505    }
1506
1507    pub fn rendering_mode(&self) -> ImageRendering {
1511        self.rendering_mode
1512    }
1513
1514    pub fn kind(&self) -> &ImageKind {
1516        &self.kind
1517    }
1518
1519    pub fn abs_transform(&self) -> Transform {
1526        self.abs_transform
1527    }
1528
1529    pub fn bounding_box(&self) -> Rect {
1533        self.size.to_rect(0.0, 0.0).unwrap()
1534    }
1535
1536    pub fn abs_bounding_box(&self) -> Rect {
1540        self.abs_bounding_box.to_rect()
1541    }
1542
1543    fn subroots(&self, f: &mut dyn FnMut(&Group)) {
1544        if let ImageKind::SVG(ref tree) = self.kind {
1545            f(&tree.root)
1546        }
1547    }
1548}
1549
1550#[allow(missing_debug_implementations)]
1552#[derive(Clone, Debug)]
1553pub struct Tree {
1554    pub(crate) size: Size,
1555    pub(crate) root: Group,
1556    pub(crate) linear_gradients: Vec<Arc<LinearGradient>>,
1557    pub(crate) radial_gradients: Vec<Arc<RadialGradient>>,
1558    pub(crate) patterns: Vec<Arc<Pattern>>,
1559    pub(crate) clip_paths: Vec<Arc<ClipPath>>,
1560    pub(crate) masks: Vec<Arc<Mask>>,
1561    pub(crate) filters: Vec<Arc<filter::Filter>>,
1562    #[cfg(feature = "text")]
1563    pub(crate) fontdb: Arc<fontdb::Database>,
1564}
1565
1566impl Tree {
1567    pub fn size(&self) -> Size {
1573        self.size
1574    }
1575
1576    pub fn root(&self) -> &Group {
1578        &self.root
1579    }
1580
1581    pub fn node_by_id(&self, id: &str) -> Option<&Node> {
1585        if id.is_empty() {
1586            return None;
1587        }
1588
1589        node_by_id(&self.root, id)
1590    }
1591
1592    pub fn has_text_nodes(&self) -> bool {
1594        has_text_nodes(&self.root)
1595    }
1596
1597    pub fn linear_gradients(&self) -> &[Arc<LinearGradient>] {
1599        &self.linear_gradients
1600    }
1601
1602    pub fn radial_gradients(&self) -> &[Arc<RadialGradient>] {
1604        &self.radial_gradients
1605    }
1606
1607    pub fn patterns(&self) -> &[Arc<Pattern>] {
1609        &self.patterns
1610    }
1611
1612    pub fn clip_paths(&self) -> &[Arc<ClipPath>] {
1614        &self.clip_paths
1615    }
1616
1617    pub fn masks(&self) -> &[Arc<Mask>] {
1619        &self.masks
1620    }
1621
1622    pub fn filters(&self) -> &[Arc<filter::Filter>] {
1624        &self.filters
1625    }
1626
1627    #[cfg(feature = "text")]
1629    pub fn fontdb(&self) -> &Arc<fontdb::Database> {
1630        &self.fontdb
1631    }
1632
1633    pub(crate) fn collect_paint_servers(&mut self) {
1634        loop_over_paint_servers(&self.root, &mut |paint| match paint {
1635            Paint::Color(_) => {}
1636            Paint::LinearGradient(lg) => {
1637                if !self
1638                    .linear_gradients
1639                    .iter()
1640                    .any(|other| Arc::ptr_eq(lg, other))
1641                {
1642                    self.linear_gradients.push(lg.clone());
1643                }
1644            }
1645            Paint::RadialGradient(rg) => {
1646                if !self
1647                    .radial_gradients
1648                    .iter()
1649                    .any(|other| Arc::ptr_eq(rg, other))
1650                {
1651                    self.radial_gradients.push(rg.clone());
1652                }
1653            }
1654            Paint::Pattern(patt) => {
1655                if !self.patterns.iter().any(|other| Arc::ptr_eq(patt, other)) {
1656                    self.patterns.push(patt.clone());
1657                }
1658            }
1659        });
1660    }
1661}
1662
1663fn node_by_id<'a>(parent: &'a Group, id: &str) -> Option<&'a Node> {
1664    for child in &parent.children {
1665        if child.id() == id {
1666            return Some(child);
1667        }
1668
1669        if let Node::Group(ref g) = child {
1670            if let Some(n) = node_by_id(g, id) {
1671                return Some(n);
1672            }
1673        }
1674    }
1675
1676    None
1677}
1678
1679fn has_text_nodes(root: &Group) -> bool {
1680    for node in &root.children {
1681        if let Node::Text(_) = node {
1682            return true;
1683        }
1684
1685        let mut has_text = false;
1686
1687        if let Node::Image(ref image) = node {
1688            if let ImageKind::SVG(ref tree) = image.kind {
1689                if has_text_nodes(&tree.root) {
1690                    has_text = true;
1691                }
1692            }
1693        }
1694
1695        node.subroots(|subroot| has_text |= has_text_nodes(subroot));
1696
1697        if has_text {
1698            return true;
1699        }
1700    }
1701
1702    true
1703}
1704
1705fn loop_over_paint_servers(parent: &Group, f: &mut dyn FnMut(&Paint)) {
1706    fn push(paint: Option<&Paint>, f: &mut dyn FnMut(&Paint)) {
1707        if let Some(paint) = paint {
1708            f(paint);
1709        }
1710    }
1711
1712    for node in &parent.children {
1713        match node {
1714            Node::Group(ref group) => loop_over_paint_servers(group, f),
1715            Node::Path(ref path) => {
1716                push(path.fill.as_ref().map(|f| &f.paint), f);
1717                push(path.stroke.as_ref().map(|f| &f.paint), f);
1718            }
1719            Node::Image(_) => {}
1720            Node::Text(_) => {}
1722        }
1723
1724        node.subroots(|subroot| loop_over_paint_servers(subroot, f));
1725    }
1726}
1727
1728impl Group {
1729    pub(crate) fn collect_clip_paths(&self, clip_paths: &mut Vec<Arc<ClipPath>>) {
1730        for node in self.children() {
1731            if let Node::Group(ref g) = node {
1732                if let Some(ref clip) = g.clip_path {
1733                    if !clip_paths.iter().any(|other| Arc::ptr_eq(clip, other)) {
1734                        clip_paths.push(clip.clone());
1735                    }
1736
1737                    if let Some(ref sub_clip) = clip.clip_path {
1738                        if !clip_paths.iter().any(|other| Arc::ptr_eq(sub_clip, other)) {
1739                            clip_paths.push(sub_clip.clone());
1740                        }
1741                    }
1742                }
1743            }
1744
1745            node.subroots(|subroot| subroot.collect_clip_paths(clip_paths));
1746
1747            if let Node::Group(ref g) = node {
1748                g.collect_clip_paths(clip_paths);
1749            }
1750        }
1751    }
1752
1753    pub(crate) fn collect_masks(&self, masks: &mut Vec<Arc<Mask>>) {
1754        for node in self.children() {
1755            if let Node::Group(ref g) = node {
1756                if let Some(ref mask) = g.mask {
1757                    if !masks.iter().any(|other| Arc::ptr_eq(mask, other)) {
1758                        masks.push(mask.clone());
1759                    }
1760
1761                    if let Some(ref sub_mask) = mask.mask {
1762                        if !masks.iter().any(|other| Arc::ptr_eq(sub_mask, other)) {
1763                            masks.push(sub_mask.clone());
1764                        }
1765                    }
1766                }
1767            }
1768
1769            node.subroots(|subroot| subroot.collect_masks(masks));
1770
1771            if let Node::Group(ref g) = node {
1772                g.collect_masks(masks);
1773            }
1774        }
1775    }
1776
1777    pub(crate) fn collect_filters(&self, filters: &mut Vec<Arc<filter::Filter>>) {
1778        for node in self.children() {
1779            if let Node::Group(ref g) = node {
1780                for filter in g.filters() {
1781                    if !filters.iter().any(|other| Arc::ptr_eq(filter, other)) {
1782                        filters.push(filter.clone());
1783                    }
1784                }
1785            }
1786
1787            node.subroots(|subroot| subroot.collect_filters(filters));
1788
1789            if let Node::Group(ref g) = node {
1790                g.collect_filters(filters);
1791            }
1792        }
1793    }
1794
1795    pub(crate) fn calculate_object_bbox(&mut self) -> Option<NonZeroRect> {
1796        let mut bbox = BBox::default();
1797        for child in &self.children {
1798            let mut c_bbox = child.bounding_box();
1799            if let Node::Group(ref group) = child {
1800                if let Some(r) = c_bbox.transform(group.transform) {
1801                    c_bbox = r;
1802                }
1803            }
1804
1805            bbox = bbox.expand(c_bbox);
1806        }
1807
1808        bbox.to_non_zero_rect()
1809    }
1810
1811    pub(crate) fn calculate_bounding_boxes(&mut self) -> Option<()> {
1812        let mut bbox = BBox::default();
1813        let mut abs_bbox = BBox::default();
1814        let mut stroke_bbox = BBox::default();
1815        let mut abs_stroke_bbox = BBox::default();
1816        let mut layer_bbox = BBox::default();
1817        for child in &self.children {
1818            {
1819                let mut c_bbox = child.bounding_box();
1820                if let Node::Group(ref group) = child {
1821                    if let Some(r) = c_bbox.transform(group.transform) {
1822                        c_bbox = r;
1823                    }
1824                }
1825
1826                bbox = bbox.expand(c_bbox);
1827            }
1828
1829            abs_bbox = abs_bbox.expand(child.abs_bounding_box());
1830
1831            {
1832                let mut c_bbox = child.stroke_bounding_box();
1833                if let Node::Group(ref group) = child {
1834                    if let Some(r) = c_bbox.transform(group.transform) {
1835                        c_bbox = r;
1836                    }
1837                }
1838
1839                stroke_bbox = stroke_bbox.expand(c_bbox);
1840            }
1841
1842            abs_stroke_bbox = abs_stroke_bbox.expand(child.abs_stroke_bounding_box());
1843
1844            if let Node::Group(ref group) = child {
1845                let r = group.layer_bounding_box;
1846                if let Some(r) = r.transform(group.transform) {
1847                    layer_bbox = layer_bbox.expand(r);
1848                }
1849            } else {
1850                layer_bbox = layer_bbox.expand(child.stroke_bounding_box());
1852            }
1853        }
1854
1855        if let Some(bbox) = bbox.to_rect() {
1858            self.bounding_box = bbox;
1859            self.abs_bounding_box = abs_bbox.to_rect()?;
1860            self.stroke_bounding_box = stroke_bbox.to_rect()?;
1861            self.abs_stroke_bounding_box = abs_stroke_bbox.to_rect()?;
1862        }
1863
1864        if let Some(filter_bbox) = self.filters_bounding_box() {
1866            self.layer_bounding_box = filter_bbox;
1867        } else {
1868            self.layer_bounding_box = layer_bbox.to_non_zero_rect()?;
1869        }
1870
1871        self.abs_layer_bounding_box = self.layer_bounding_box.transform(self.abs_transform)?;
1872
1873        Some(())
1874    }
1875}