telar_geometry_core/
object_fit.rs1use crate::Rect;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum ObjectFit {
6 Fill,
8 #[default]
10 Contain,
11 Cover,
13}
14
15pub fn fit_rect(intrinsic: (f32, f32), container: Rect, fit: ObjectFit) -> (Rect, bool) {
20 let (iw, ih) = intrinsic;
21 if iw <= 0.0 || ih <= 0.0 || container.width <= 0.0 || container.height <= 0.0 {
23 return (container, false);
24 }
25 match fit {
26 ObjectFit::Fill => (container, false),
27 ObjectFit::Contain | ObjectFit::Cover => {
28 let sx = container.width / iw;
29 let sy = container.height / ih;
30 let (s, clip) = if fit == ObjectFit::Contain {
31 (sx.min(sy), false)
32 } else {
33 (sx.max(sy), true)
34 };
35 let w = iw * s;
36 let h = ih * s;
37 let x = container.x + (container.width - w) * 0.5;
38 let y = container.y + (container.height - h) * 0.5;
39 (Rect::new(x, y, w, h), clip)
40 }
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn fill_returns_container_and_no_clip() {
50 let c = Rect::new(0.0, 0.0, 120.0, 60.0);
51 let (rect, clip) = fit_rect((10.0, 10.0), c, ObjectFit::Fill);
52 assert_eq!(rect, c);
53 assert!(!clip);
54 }
55
56 #[test]
57 fn contain_letterboxes_wide_box() {
58 let c = Rect::new(0.0, 0.0, 120.0, 60.0);
60 let (rect, clip) = fit_rect((10.0, 10.0), c, ObjectFit::Contain);
61 assert_eq!(rect, Rect::new(30.0, 0.0, 60.0, 60.0));
62 assert!(!clip);
63 }
64
65 #[test]
66 fn cover_overflows_and_clips() {
67 let c = Rect::new(0.0, 0.0, 120.0, 60.0);
69 let (rect, clip) = fit_rect((10.0, 10.0), c, ObjectFit::Cover);
70 assert_eq!(rect, Rect::new(0.0, -30.0, 120.0, 120.0));
71 assert!(clip);
72 }
73
74 #[test]
75 fn contain_respects_container_origin() {
76 let c = Rect::new(5.0, 7.0, 120.0, 60.0);
77 let (rect, _) = fit_rect((10.0, 10.0), c, ObjectFit::Contain);
78 assert_eq!(rect, Rect::new(35.0, 7.0, 60.0, 60.0));
79 }
80
81 #[test]
82 fn degenerate_intrinsic_fills() {
83 let c = Rect::new(0.0, 0.0, 120.0, 60.0);
84 let (rect, clip) = fit_rect((0.0, 10.0), c, ObjectFit::Contain);
85 assert_eq!(rect, c);
86 assert!(!clip);
87 }
88
89 #[test]
90 fn default_is_contain() {
91 assert_eq!(ObjectFit::default(), ObjectFit::Contain);
92 }
93}