14
14
15
15
//! An SVG widget.
16
16
17
- use druid ;
18
- use druid :: RenderContext ;
17
+ use std :: sync :: Arc ;
18
+
19
19
use resvg;
20
+ use usvg:: Tree ;
21
+
22
+ use crate :: piet:: { ImageBuf , ImageFormat , InterpolationMode } ;
23
+ use crate :: widget:: prelude:: * ;
24
+ use crate :: { Rect , ScaledArea } ;
20
25
21
26
#[ allow( dead_code) ]
22
- pub fn new ( data : impl Into < std :: sync :: Arc < usvg :: Tree > > ) -> Svg {
27
+ pub fn new ( data : impl Into < Arc < Tree > > ) -> Svg {
23
28
Svg :: new ( data. into ( ) )
24
29
}
25
30
@@ -31,27 +36,28 @@ pub fn from_str(s: &str) -> Result<SvgData, <SvgData as std::str::FromStr>::Err>
31
36
32
37
/// A widget that renders a SVG
33
38
pub struct Svg {
34
- tree : std :: sync :: Arc < usvg :: Tree > ,
35
- default_size : druid :: Size ,
36
- cached : Option < ( druid :: Size , druid :: piet :: ImageBuf ) > ,
39
+ tree : Arc < Tree > ,
40
+ default_size : Size ,
41
+ cached : Option < ImageBuf > ,
37
42
}
38
43
39
44
impl Svg {
40
45
/// Create an SVG-drawing widget from SvgData.
41
46
///
42
47
/// The SVG will scale to fit its box constraints.
43
- pub fn new ( tree : impl Into < std :: sync :: Arc < usvg :: Tree > > ) -> Self {
48
+ pub fn new ( tree : impl Into < Arc < Tree > > ) -> Self {
44
49
let tree = tree. into ( ) ;
45
50
Svg {
46
- default_size : druid :: Size :: new ( tree. size . width ( ) , tree. size . height ( ) ) ,
47
- cached : None :: < ( druid :: Size , druid :: piet :: ImageBuf ) > ,
51
+ default_size : Size :: new ( tree. size . width ( ) , tree. size . height ( ) ) ,
52
+ cached : None ,
48
53
tree,
49
54
}
50
55
}
51
56
52
- fn render ( & self , size : druid:: Size ) -> Option < druid:: piet:: ImageBuf > {
53
- let fit = usvg:: FitTo :: Size ( size. width as u32 , size. height as u32 ) ;
54
- let mut pixmap = tiny_skia:: Pixmap :: new ( size. width as u32 , size. height as u32 ) . unwrap ( ) ;
57
+ fn render ( & self , size_px : Size ) -> Option < ImageBuf > {
58
+ let fit = usvg:: FitTo :: Size ( size_px. width as u32 , size_px. height as u32 ) ;
59
+ let mut pixmap =
60
+ tiny_skia:: Pixmap :: new ( size_px. width as u32 , size_px. height as u32 ) . unwrap ( ) ;
55
61
56
62
if resvg:: render (
57
63
& self . tree ,
@@ -65,85 +71,69 @@ impl Svg {
65
71
return None ;
66
72
}
67
73
68
- Some ( druid :: piet :: ImageBuf :: from_raw (
74
+ Some ( ImageBuf :: from_raw (
69
75
pixmap. data ( ) ,
70
- druid :: piet :: ImageFormat :: RgbaPremul ,
71
- size . width as usize ,
72
- size . height as usize ,
76
+ ImageFormat :: RgbaPremul ,
77
+ size_px . width as usize ,
78
+ size_px . height as usize ,
73
79
) )
74
80
}
75
81
}
76
82
77
- impl < T : druid:: Data > druid:: Widget < T > for Svg {
78
- fn event (
79
- & mut self ,
80
- _ctx : & mut druid:: EventCtx ,
81
- _event : & druid:: Event ,
82
- _data : & mut T ,
83
- _env : & druid:: Env ,
84
- ) {
85
- }
83
+ impl < T : Data > Widget < T > for Svg {
84
+ fn event ( & mut self , _ctx : & mut EventCtx , _event : & Event , _data : & mut T , _env : & Env ) { }
86
85
87
- fn lifecycle (
88
- & mut self ,
89
- _ctx : & mut druid:: LifeCycleCtx ,
90
- _event : & druid:: LifeCycle ,
91
- _data : & T ,
92
- _env : & druid:: Env ,
93
- ) {
94
- }
86
+ fn lifecycle ( & mut self , _ctx : & mut LifeCycleCtx , _event : & LifeCycle , _data : & T , _env : & Env ) { }
95
87
96
- fn update ( & mut self , _ctx : & mut druid:: UpdateCtx , _old_data : & T , _data : & T , _env : & druid:: Env ) {
97
- }
88
+ fn update ( & mut self , _ctx : & mut UpdateCtx , _old_data : & T , _data : & T , _env : & Env ) { }
98
89
99
90
fn layout (
100
91
& mut self ,
101
- _layout_ctx : & mut druid :: LayoutCtx ,
102
- bc : & druid :: BoxConstraints ,
92
+ _layout_ctx : & mut LayoutCtx ,
93
+ bc : & BoxConstraints ,
103
94
_data : & T ,
104
- _env : & druid :: Env ,
105
- ) -> druid :: Size {
95
+ _env : & Env ,
96
+ ) -> Size {
106
97
// preferred size comes from the svg
107
98
let size = self . default_size ;
108
99
bc. constrain_aspect_ratio ( size. height / size. width , size. width )
109
100
}
110
101
111
- fn paint ( & mut self , ctx : & mut druid :: PaintCtx , _data : & T , _env : & druid :: Env ) {
102
+ fn paint ( & mut self , ctx : & mut PaintCtx , _data : & T , _env : & Env ) {
112
103
let size = ctx. size ( ) ;
104
+ let area = ScaledArea :: from_dp ( size, ctx. scale ( ) ) ;
105
+ let size_px = area. size_px ( ) ;
113
106
114
- let cached = self . cached . as_ref ( ) . filter ( |( csize, _) | * csize == size) ;
115
- let cached = match cached {
116
- Some ( current) => Some ( current. clone ( ) ) ,
117
- None => self . render ( size) . map ( |i| ( size, i) ) ,
118
- } ;
119
- let cached = match cached {
120
- Some ( current) => current,
121
- None => {
122
- tracing:: error!( "unable to paint svg" ) ;
123
- return ;
124
- }
125
- } ;
107
+ let needs_render = self
108
+ . cached
109
+ . as_ref ( )
110
+ . filter ( |image_buf| image_buf. size ( ) == size_px)
111
+ . is_none ( ) ;
112
+
113
+ if needs_render {
114
+ self . cached = self . render ( size_px) ;
115
+ }
116
+
117
+ if self . cached . is_none ( ) {
118
+ tracing:: error!( "unable to paint SVG due to no rendered image" ) ;
119
+ return ;
120
+ }
126
121
127
- let clip_rect = druid :: Rect :: ZERO . with_size ( cached . 0 ) ;
128
- let img = cached. 1 . to_image ( ctx. render_ctx ) ;
122
+ let clip_rect = Rect :: ZERO . with_size ( size ) ;
123
+ let img = self . cached . as_ref ( ) . unwrap ( ) . to_image ( ctx. render_ctx ) ;
129
124
ctx. clip ( clip_rect) ;
130
- ctx. draw_image (
131
- & img,
132
- clip_rect,
133
- druid:: piet:: InterpolationMode :: NearestNeighbor ,
134
- ) ;
135
- self . cached = Some ( cached) ;
125
+ ctx. draw_image ( & img, clip_rect, InterpolationMode :: NearestNeighbor ) ;
136
126
}
137
127
}
138
128
139
129
/// Stored parsed SVG tree.
140
- #[ derive( Clone , druid :: Data ) ]
130
+ #[ derive( Clone , Data ) ]
141
131
pub struct SvgData {
142
- tree : std :: sync :: Arc < usvg :: Tree > ,
132
+ tree : Arc < Tree > ,
143
133
}
144
134
145
135
impl SvgData {
146
- fn new ( tree : std :: sync :: Arc < usvg :: Tree > ) -> Self {
136
+ fn new ( tree : Arc < Tree > ) -> Self {
147
137
Self { tree }
148
138
}
149
139
@@ -171,14 +161,14 @@ impl std::str::FromStr for SvgData {
171
161
..usvg:: Options :: default ( )
172
162
} ;
173
163
174
- match usvg :: Tree :: from_str ( svg_str, & re_opt) {
175
- Ok ( tree) => Ok ( SvgData :: new ( std :: sync :: Arc :: new ( tree) ) ) ,
164
+ match Tree :: from_str ( svg_str, & re_opt) {
165
+ Ok ( tree) => Ok ( SvgData :: new ( Arc :: new ( tree) ) ) ,
176
166
Err ( err) => Err ( err. into ( ) ) ,
177
167
}
178
168
}
179
169
}
180
170
181
- impl From < SvgData > for std :: sync :: Arc < usvg :: Tree > {
171
+ impl From < SvgData > for Arc < Tree > {
182
172
fn from ( d : SvgData ) -> Self {
183
173
d. tree
184
174
}
0 commit comments