xref: /aosp_15_r20/external/crosvm/gpu_display/src/gpu_display_win/math_util.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::any::type_name;
6 use std::fmt;
7 
8 use euclid::point2;
9 use euclid::size2;
10 use euclid::Size2D;
11 use num_traits::NumCast;
12 use winapi::shared::windef::LPPOINT;
13 use winapi::shared::windef::POINT;
14 use winapi::shared::windef::RECT;
15 
16 use super::HostWindowSpace;
17 
18 pub type Point = euclid::Point2D<i32, HostWindowSpace>;
19 pub type Rect = euclid::Rect<i32, HostWindowSpace>;
20 pub type Size = euclid::Size2D<i32, HostWindowSpace>;
21 
22 pub trait SizeExtension {
create_and_enforce_aspect_ratio( original_size: &Self, expected_aspect_ratio: f32, should_adjust_width: bool, ) -> Self23     fn create_and_enforce_aspect_ratio(
24         original_size: &Self,
25         expected_aspect_ratio: f32,
26         should_adjust_width: bool,
27     ) -> Self;
28     #[allow(dead_code)]
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self29     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self;
30     #[allow(dead_code)]
scale(&self, ratio: f32) -> Self31     fn scale(&self, ratio: f32) -> Self;
32     #[allow(dead_code)]
transpose(&self) -> Self33     fn transpose(&self) -> Self;
34     #[allow(dead_code)]
shorter_edge(&self) -> i3235     fn shorter_edge(&self) -> i32;
aspect_ratio(&self) -> f3236     fn aspect_ratio(&self) -> f32;
37     #[allow(dead_code)]
is_square(&self) -> bool38     fn is_square(&self) -> bool;
39     #[allow(dead_code)]
is_landscape(&self) -> bool40     fn is_landscape(&self) -> bool;
41 }
42 
43 impl SizeExtension for Size {
create_and_enforce_aspect_ratio( original_size: &Self, expected_aspect_ratio: f32, should_adjust_width: bool, ) -> Self44     fn create_and_enforce_aspect_ratio(
45         original_size: &Self,
46         expected_aspect_ratio: f32,
47         should_adjust_width: bool,
48     ) -> Self {
49         let mut size = *original_size;
50         if should_adjust_width {
51             size.width = (size.height as f32 * expected_aspect_ratio).round() as i32;
52         } else {
53             size.height = (size.width as f32 / expected_aspect_ratio).round() as i32;
54         }
55         size
56     }
57 
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self58     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self {
59         Size::create_and_enforce_aspect_ratio(
60             original_size,
61             expected_aspect_ratio,
62             /* should_adjust_width */ original_size.aspect_ratio() > expected_aspect_ratio,
63         )
64     }
65 
66     #[inline]
scale(&self, ratio: f32) -> Self67     fn scale(&self, ratio: f32) -> Self {
68         size2(
69             (self.width as f32 * ratio) as i32,
70             (self.height as f32 * ratio) as i32,
71         )
72     }
73 
74     #[inline]
transpose(&self) -> Self75     fn transpose(&self) -> Self {
76         size2(self.height, self.width)
77     }
78 
79     #[inline]
shorter_edge(&self) -> i3280     fn shorter_edge(&self) -> i32 {
81         std::cmp::min(self.width, self.height)
82     }
83 
84     #[inline]
aspect_ratio(&self) -> f3285     fn aspect_ratio(&self) -> f32 {
86         self.width as f32 / self.height as f32
87     }
88 
89     #[inline]
is_square(&self) -> bool90     fn is_square(&self) -> bool {
91         self.width == self.height
92     }
93 
94     #[inline]
is_landscape(&self) -> bool95     fn is_landscape(&self) -> bool {
96         self.width > self.height
97     }
98 }
99 
100 pub trait RectExtension {
to_sys_rect(&self) -> RECT101     fn to_sys_rect(&self) -> RECT;
102 }
103 
104 impl RectExtension for Rect {
105     #[inline]
to_sys_rect(&self) -> RECT106     fn to_sys_rect(&self) -> RECT {
107         RECT {
108             left: self.min_x(),
109             top: self.min_y(),
110             right: self.max_x(),
111             bottom: self.max_y(),
112         }
113     }
114 }
115 
116 pub trait SysRectExtension {
to_rect(&self) -> Rect117     fn to_rect(&self) -> Rect;
118 }
119 
120 impl SysRectExtension for RECT {
121     #[inline]
to_rect(&self) -> Rect122     fn to_rect(&self) -> Rect {
123         Rect::new(
124             point2(self.left, self.top),
125             size2(self.right - self.left, self.bottom - self.top),
126         )
127     }
128 }
129 
130 pub trait PointExtension {
to_sys_point(&self) -> POINT131     fn to_sys_point(&self) -> POINT;
132 }
133 
134 impl PointExtension for Point {
135     #[inline]
to_sys_point(&self) -> POINT136     fn to_sys_point(&self) -> POINT {
137         POINT {
138             x: self.x,
139             y: self.y,
140         }
141     }
142 }
143 
144 pub trait SysPointExtension {
to_point(&self) -> Point145     fn to_point(&self) -> Point;
as_mut_ptr(&mut self) -> LPPOINT146     fn as_mut_ptr(&mut self) -> LPPOINT;
147 }
148 
149 impl SysPointExtension for POINT {
150     #[inline]
to_point(&self) -> Point151     fn to_point(&self) -> Point {
152         point2(self.x, self.y)
153     }
154 
155     #[inline]
as_mut_ptr(&mut self) -> LPPOINT156     fn as_mut_ptr(&mut self) -> LPPOINT {
157         self as LPPOINT
158     }
159 }
160 
161 pub trait Size2DCheckedCast<U>: Sized {
checked_cast<T: NumCast>(self) -> Size2D<T, U>162     fn checked_cast<T: NumCast>(self) -> Size2D<T, U>;
163 }
164 
165 impl<T, U> Size2DCheckedCast<U> for Size2D<T, U>
166 where
167     T: NumCast + Copy + fmt::Debug,
168 {
checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U>169     fn checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U> {
170         self.try_cast::<NewT>().unwrap_or_else(|| {
171             panic!(
172                 "Cannot cast {:?} from {} to {}",
173                 self,
174                 type_name::<T>(),
175                 type_name::<NewT>(),
176             )
177         })
178     }
179 }
180 
181 #[cfg(test)]
182 mod tests {
183     use super::*;
184 
185     #[test]
largest_inner_rect_size_when_outer_is_wider()186     fn largest_inner_rect_size_when_outer_is_wider() {
187         assert_eq!(
188             Size::get_largest_inner_rect_size(
189                 /* original_size */ &size2(1600, 900),
190                 /* expected_aspect_ratio */ 0.5
191             ),
192             size2(450, 900)
193         );
194     }
195 
196     #[test]
largest_inner_rect_size_when_outer_is_taller()197     fn largest_inner_rect_size_when_outer_is_taller() {
198         assert_eq!(
199             Size::get_largest_inner_rect_size(
200                 /* original_size */ &size2(900, 1600),
201                 /* expected_aspect_ratio */ 3.0
202             ),
203             size2(900, 300)
204         );
205     }
206 }
207