• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::POINT;
13 use winapi::shared::windef::RECT;
14 
15 use super::HostWindowSpace;
16 
17 pub type Point = euclid::Point2D<i32, HostWindowSpace>;
18 pub type Rect = euclid::Rect<i32, HostWindowSpace>;
19 pub type Size = euclid::Size2D<i32, HostWindowSpace>;
20 
21 pub trait SizeExtension {
create_and_enforce_aspect_ratio( original_size: &Self, expected_aspect_ratio: f32, should_adjust_width: bool, ) -> Self22     fn create_and_enforce_aspect_ratio(
23         original_size: &Self,
24         expected_aspect_ratio: f32,
25         should_adjust_width: bool,
26     ) -> Self;
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self27     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self;
scale(&self, ratio: f32) -> Self28     fn scale(&self, ratio: f32) -> Self;
transpose(&self) -> Self29     fn transpose(&self) -> Self;
shorter_edge(&self) -> i3230     fn shorter_edge(&self) -> i32;
aspect_ratio(&self) -> f3231     fn aspect_ratio(&self) -> f32;
is_square(&self) -> bool32     fn is_square(&self) -> bool;
is_landscape(&self) -> bool33     fn is_landscape(&self) -> bool;
34 }
35 
36 impl SizeExtension for Size {
create_and_enforce_aspect_ratio( original_size: &Self, expected_aspect_ratio: f32, should_adjust_width: bool, ) -> Self37     fn create_and_enforce_aspect_ratio(
38         original_size: &Self,
39         expected_aspect_ratio: f32,
40         should_adjust_width: bool,
41     ) -> Self {
42         let mut size = *original_size;
43         if should_adjust_width {
44             size.width = (size.height as f32 * expected_aspect_ratio).round() as i32;
45         } else {
46             size.height = (size.width as f32 / expected_aspect_ratio).round() as i32;
47         }
48         size
49     }
50 
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self51     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self {
52         Size::create_and_enforce_aspect_ratio(
53             original_size,
54             expected_aspect_ratio,
55             /* should_adjust_width */ original_size.aspect_ratio() > expected_aspect_ratio,
56         )
57     }
58 
59     #[inline]
scale(&self, ratio: f32) -> Self60     fn scale(&self, ratio: f32) -> Self {
61         size2(
62             (self.width as f32 * ratio) as i32,
63             (self.height as f32 * ratio) as i32,
64         )
65     }
66 
67     #[inline]
transpose(&self) -> Self68     fn transpose(&self) -> Self {
69         size2(self.height, self.width)
70     }
71 
72     #[inline]
shorter_edge(&self) -> i3273     fn shorter_edge(&self) -> i32 {
74         std::cmp::min(self.width, self.height)
75     }
76 
77     #[inline]
aspect_ratio(&self) -> f3278     fn aspect_ratio(&self) -> f32 {
79         self.width as f32 / self.height as f32
80     }
81 
82     #[inline]
is_square(&self) -> bool83     fn is_square(&self) -> bool {
84         self.width == self.height
85     }
86 
87     #[inline]
is_landscape(&self) -> bool88     fn is_landscape(&self) -> bool {
89         self.width > self.height
90     }
91 }
92 
93 pub trait RectExtension {
to_sys_rect(&self) -> RECT94     fn to_sys_rect(&self) -> RECT;
95 }
96 
97 impl RectExtension for Rect {
98     #[inline]
to_sys_rect(&self) -> RECT99     fn to_sys_rect(&self) -> RECT {
100         RECT {
101             left: self.min_x(),
102             top: self.min_y(),
103             right: self.max_x(),
104             bottom: self.max_y(),
105         }
106     }
107 }
108 
109 pub trait SysRectExtension {
to_rect(&self) -> Rect110     fn to_rect(&self) -> Rect;
111 }
112 
113 impl SysRectExtension for RECT {
114     #[inline]
to_rect(&self) -> Rect115     fn to_rect(&self) -> Rect {
116         Rect::new(
117             point2(self.left, self.top),
118             size2(self.right - self.left, self.bottom - self.top),
119         )
120     }
121 }
122 
123 pub trait PointExtension {
to_sys_point(&self) -> POINT124     fn to_sys_point(&self) -> POINT;
125 }
126 
127 impl PointExtension for Point {
128     #[inline]
to_sys_point(&self) -> POINT129     fn to_sys_point(&self) -> POINT {
130         POINT {
131             x: self.x,
132             y: self.y,
133         }
134     }
135 }
136 
137 pub trait SysPointExtension {
to_point(&self) -> Point138     fn to_point(&self) -> Point;
139 }
140 
141 impl SysPointExtension for POINT {
142     #[inline]
to_point(&self) -> Point143     fn to_point(&self) -> Point {
144         point2(self.x, self.y)
145     }
146 }
147 
148 pub trait Size2DCheckedCast<U>: Sized {
checked_cast<T: NumCast>(self) -> Size2D<T, U>149     fn checked_cast<T: NumCast>(self) -> Size2D<T, U>;
150 }
151 
152 impl<T, U> Size2DCheckedCast<U> for Size2D<T, U>
153 where
154     T: NumCast + Copy + fmt::Debug,
155 {
checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U>156     fn checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U> {
157         self.try_cast::<NewT>().unwrap_or_else(|| {
158             panic!(
159                 "Cannot cast {:?} from {} to {}",
160                 self,
161                 type_name::<T>(),
162                 type_name::<NewT>(),
163             )
164         })
165     }
166 }
167 
168 #[cfg(test)]
169 mod tests {
170     use super::*;
171 
172     #[test]
largest_inner_rect_size_when_outer_is_wider()173     fn largest_inner_rect_size_when_outer_is_wider() {
174         assert_eq!(
175             Size::get_largest_inner_rect_size(
176                 /* original_size */ &size2(1600, 900),
177                 /* expected_aspect_ratio */ 0.5
178             ),
179             size2(450, 900)
180         );
181     }
182 
183     #[test]
largest_inner_rect_size_when_outer_is_taller()184     fn largest_inner_rect_size_when_outer_is_taller() {
185         assert_eq!(
186             Size::get_largest_inner_rect_size(
187                 /* original_size */ &size2(900, 1600),
188                 /* expected_aspect_ratio */ 3.0
189             ),
190             size2(900, 300)
191         );
192     }
193 }
194