1414
1515//! An SVG widget.
1616
17- use druid ;
18- use druid :: RenderContext ;
17+ use std :: sync :: Arc ;
18+
1919use resvg;
20+ use usvg:: Tree ;
21+
22+ use crate :: piet:: { ImageBuf , ImageFormat , InterpolationMode } ;
23+ use crate :: widget:: prelude:: * ;
24+ use crate :: { Rect , ScaledArea } ;
2025
2126#[ 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 {
2328 Svg :: new ( data. into ( ) )
2429}
2530
@@ -31,27 +36,28 @@ pub fn from_str(s: &str) -> Result<SvgData, <SvgData as std::str::FromStr>::Err>
3136
3237/// A widget that renders a SVG
3338pub 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 > ,
3742}
3843
3944impl Svg {
4045 /// Create an SVG-drawing widget from SvgData.
4146 ///
4247 /// 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 {
4449 let tree = tree. into ( ) ;
4550 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 ,
4853 tree,
4954 }
5055 }
5156
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 ( ) ;
5561
5662 if resvg:: render (
5763 & self . tree ,
@@ -65,85 +71,69 @@ impl Svg {
6571 return None ;
6672 }
6773
68- Some ( druid :: piet :: ImageBuf :: from_raw (
74+ Some ( ImageBuf :: from_raw (
6975 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 ,
7379 ) )
7480 }
7581}
7682
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 ) { }
8685
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 ) { }
9587
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 ) { }
9889
9990 fn layout (
10091 & mut self ,
101- _layout_ctx : & mut druid :: LayoutCtx ,
102- bc : & druid :: BoxConstraints ,
92+ _layout_ctx : & mut LayoutCtx ,
93+ bc : & BoxConstraints ,
10394 _data : & T ,
104- _env : & druid :: Env ,
105- ) -> druid :: Size {
95+ _env : & Env ,
96+ ) -> Size {
10697 // preferred size comes from the svg
10798 let size = self . default_size ;
10899 bc. constrain_aspect_ratio ( size. height / size. width , size. width )
109100 }
110101
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 ) {
112103 let size = ctx. size ( ) ;
104+ let area = ScaledArea :: from_dp ( size, ctx. scale ( ) ) ;
105+ let size_px = area. size_px ( ) ;
113106
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+ }
126121
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 ) ;
129124 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 ) ;
136126 }
137127}
138128
139129/// Stored parsed SVG tree.
140- #[ derive( Clone , druid :: Data ) ]
130+ #[ derive( Clone , Data ) ]
141131pub struct SvgData {
142- tree : std :: sync :: Arc < usvg :: Tree > ,
132+ tree : Arc < Tree > ,
143133}
144134
145135impl SvgData {
146- fn new ( tree : std :: sync :: Arc < usvg :: Tree > ) -> Self {
136+ fn new ( tree : Arc < Tree > ) -> Self {
147137 Self { tree }
148138 }
149139
@@ -171,14 +161,14 @@ impl std::str::FromStr for SvgData {
171161 ..usvg:: Options :: default ( )
172162 } ;
173163
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) ) ) ,
176166 Err ( err) => Err ( err. into ( ) ) ,
177167 }
178168 }
179169}
180170
181- impl From < SvgData > for std :: sync :: Arc < usvg :: Tree > {
171+ impl From < SvgData > for Arc < Tree > {
182172 fn from ( d : SvgData ) -> Self {
183173 d. tree
184174 }
0 commit comments