@@ -58,9 +58,11 @@ impl From<BackgroundSource> for Background {
5858pub struct BackgroundLayer {
5959 // Current background configuration
6060 current_background : Option < Background > ,
61+ current_border : Option < cap_project:: BorderConfiguration > ,
6162
6263 // Track what we rendered last to detect changes
6364 last_rendered_background : Option < Background > ,
65+ last_rendered_border : Option < cap_project:: BorderConfiguration > ,
6466 last_rendered_size : ( u32 , u32 ) ,
6567
6668 // For image backgrounds
@@ -72,7 +74,9 @@ impl BackgroundLayer {
7274 pub fn new ( ) -> Self {
7375 Self {
7476 current_background : None ,
77+ current_border : None ,
7578 last_rendered_background : None ,
79+ last_rendered_border : None ,
7680 last_rendered_size : ( 0 , 0 ) ,
7781 image_path : None ,
7882 loaded_image : None ,
@@ -102,6 +106,41 @@ impl BackgroundLayer {
102106 }
103107 }
104108
109+ fn render_border (
110+ & self ,
111+ canvas : & Canvas ,
112+ bounds : Rect ,
113+ border : & cap_project:: BorderConfiguration ,
114+ ) {
115+ if !border. enabled || border. width <= 0.0 {
116+ return ;
117+ }
118+
119+ let mut paint = Paint :: default ( ) ;
120+ paint. set_style ( skia_safe:: PaintStyle :: Stroke ) ;
121+ paint. set_stroke_width ( border. width ) ;
122+ paint. set_anti_alias ( true ) ;
123+
124+ let alpha = ( ( border. opacity / 100.0 ) . clamp ( 0.0 , 1.0 ) * 255.0 ) as u8 ;
125+ let border_color = Color :: from_argb (
126+ alpha,
127+ ( border. color [ 0 ] >> 8 ) as u8 ,
128+ ( border. color [ 1 ] >> 8 ) as u8 ,
129+ ( border. color [ 2 ] >> 8 ) as u8 ,
130+ ) ;
131+ paint. set_color ( border_color) ;
132+
133+ let inset = border. width / 2.0 ;
134+ let border_rect = Rect :: from_xywh (
135+ bounds. left ( ) + inset,
136+ bounds. top ( ) + inset,
137+ ( bounds. width ( ) - border. width ) . max ( 0.0 ) ,
138+ ( bounds. height ( ) - border. width ) . max ( 0.0 ) ,
139+ ) ;
140+
141+ canvas. draw_rect ( border_rect, & paint) ;
142+ }
143+
105144 fn render_color ( & self , canvas : & Canvas , color : & [ u16 ; 3 ] , _bounds : Rect ) {
106145 // Convert from u16 (0-65535) to u8 (0-255)
107146 let skia_color = Color :: from_argb (
@@ -121,7 +160,6 @@ impl BackgroundLayer {
121160 angle : u16 ,
122161 bounds : Rect ,
123162 ) {
124- // Convert colors from u16 (0-65535) to u8 (0-255)
125163 let start_color = Color :: from_argb (
126164 255 , // Full opacity
127165 ( from[ 0 ] >> 8 ) as u8 ,
@@ -208,19 +246,29 @@ impl RecordableLayer for BackgroundLayer {
208246 let canvas = recorder. begin_recording ( bounds, None ) ;
209247 self . render_background ( canvas, bounds) ;
210248
249+ // Render border if enabled
250+ if let Some ( border) = & uniforms. border {
251+ if border. enabled {
252+ self . render_border ( canvas, bounds, border) ;
253+ }
254+ }
255+
211256 // Update what was last rendered
212257 self . last_rendered_background = self . current_background . clone ( ) ;
258+ self . last_rendered_border = self . current_border . clone ( ) ;
213259 self . last_rendered_size = uniforms. output_size ;
214260
215261 recorder. finish_recording_as_picture ( None )
216262 }
217263
218264 fn needs_update ( & self , uniforms : & SkiaProjectUniforms ) -> bool {
219265 let new_background = Background :: from ( uniforms. background . clone ( ) ) ;
266+ let new_border = uniforms. border . clone ( ) ;
220267 let new_size = uniforms. output_size ;
221268
222269 // Check against what was last rendered, not what's currently prepared
223270 self . last_rendered_background . as_ref ( ) != Some ( & new_background)
271+ || self . last_rendered_border != new_border
224272 || self . last_rendered_size != new_size
225273 }
226274
@@ -261,6 +309,7 @@ impl RecordableLayer for BackgroundLayer {
261309
262310 // Update current state (but not last_rendered, that happens in record())
263311 self . current_background = Some ( new_background) ;
312+ self . current_border = frame_data. uniforms . border . clone ( ) ;
264313
265314 Ok ( ( ) )
266315 }
0 commit comments