• 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::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;
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self28     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self;
scale(&self, ratio: f32) -> Self29     fn scale(&self, ratio: f32) -> Self;
transpose(&self) -> Self30     fn transpose(&self) -> Self;
shorter_edge(&self) -> i3231     fn shorter_edge(&self) -> i32;
aspect_ratio(&self) -> f3232     fn aspect_ratio(&self) -> f32;
is_square(&self) -> bool33     fn is_square(&self) -> bool;
is_landscape(&self) -> bool34     fn is_landscape(&self) -> bool;
35 }
36 
37 impl SizeExtension for Size {
create_and_enforce_aspect_ratio( original_size: &Self, expected_aspect_ratio: f32, should_adjust_width: bool, ) -> Self38     fn create_and_enforce_aspect_ratio(
39         original_size: &Self,
40         expected_aspect_ratio: f32,
41         should_adjust_width: bool,
42     ) -> Self {
43         let mut size = *original_size;
44         if should_adjust_width {
45             size.width = (size.height as f32 * expected_aspect_ratio).round() as i32;
46         } else {
47             size.height = (size.width as f32 / expected_aspect_ratio).round() as i32;
48         }
49         size
50     }
51 
get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self52     fn get_largest_inner_rect_size(original_size: &Self, expected_aspect_ratio: f32) -> Self {
53         Size::create_and_enforce_aspect_ratio(
54             original_size,
55             expected_aspect_ratio,
56             /* should_adjust_width */ original_size.aspect_ratio() > expected_aspect_ratio,
57         )
58     }
59 
60     #[inline]
scale(&self, ratio: f32) -> Self61     fn scale(&self, ratio: f32) -> Self {
62         size2(
63             (self.width as f32 * ratio) as i32,
64             (self.height as f32 * ratio) as i32,
65         )
66     }
67 
68     #[inline]
transpose(&self) -> Self69     fn transpose(&self) -> Self {
70         size2(self.height, self.width)
71     }
72 
73     #[inline]
shorter_edge(&self) -> i3274     fn shorter_edge(&self) -> i32 {
75         std::cmp::min(self.width, self.height)
76     }
77 
78     #[inline]
aspect_ratio(&self) -> f3279     fn aspect_ratio(&self) -> f32 {
80         self.width as f32 / self.height as f32
81     }
82 
83     #[inline]
is_square(&self) -> bool84     fn is_square(&self) -> bool {
85         self.width == self.height
86     }
87 
88     #[inline]
is_landscape(&self) -> bool89     fn is_landscape(&self) -> bool {
90         self.width > self.height
91     }
92 }
93 
94 pub trait RectExtension {
to_sys_rect(&self) -> RECT95     fn to_sys_rect(&self) -> RECT;
96 }
97 
98 impl RectExtension for Rect {
99     #[inline]
to_sys_rect(&self) -> RECT100     fn to_sys_rect(&self) -> RECT {
101         RECT {
102             left: self.min_x(),
103             top: self.min_y(),
104             right: self.max_x(),
105             bottom: self.max_y(),
106         }
107     }
108 }
109 
110 pub trait SysRectExtension {
to_rect(&self) -> Rect111     fn to_rect(&self) -> Rect;
112 }
113 
114 impl SysRectExtension for RECT {
115     #[inline]
to_rect(&self) -> Rect116     fn to_rect(&self) -> Rect {
117         Rect::new(
118             point2(self.left, self.top),
119             size2(self.right - self.left, self.bottom - self.top),
120         )
121     }
122 }
123 
124 pub trait PointExtension {
to_sys_point(&self) -> POINT125     fn to_sys_point(&self) -> POINT;
126 }
127 
128 impl PointExtension for Point {
129     #[inline]
to_sys_point(&self) -> POINT130     fn to_sys_point(&self) -> POINT {
131         POINT {
132             x: self.x,
133             y: self.y,
134         }
135     }
136 }
137 
138 pub trait SysPointExtension {
to_point(&self) -> Point139     fn to_point(&self) -> Point;
as_mut_ptr(&mut self) -> LPPOINT140     fn as_mut_ptr(&mut self) -> LPPOINT;
141 }
142 
143 impl SysPointExtension for POINT {
144     #[inline]
to_point(&self) -> Point145     fn to_point(&self) -> Point {
146         point2(self.x, self.y)
147     }
148 
149     #[inline]
as_mut_ptr(&mut self) -> LPPOINT150     fn as_mut_ptr(&mut self) -> LPPOINT {
151         self as LPPOINT
152     }
153 }
154 
155 pub trait Size2DCheckedCast<U>: Sized {
checked_cast<T: NumCast>(self) -> Size2D<T, U>156     fn checked_cast<T: NumCast>(self) -> Size2D<T, U>;
157 }
158 
159 impl<T, U> Size2DCheckedCast<U> for Size2D<T, U>
160 where
161     T: NumCast + Copy + fmt::Debug,
162 {
checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U>163     fn checked_cast<NewT: NumCast>(self) -> Size2D<NewT, U> {
164         self.try_cast::<NewT>().unwrap_or_else(|| {
165             panic!(
166                 "Cannot cast {:?} from {} to {}",
167                 self,
168                 type_name::<T>(),
169                 type_name::<NewT>(),
170             )
171         })
172     }
173 }
174 
175 #[cfg(test)]
176 mod tests {
177     use super::*;
178 
179     #[test]
largest_inner_rect_size_when_outer_is_wider()180     fn largest_inner_rect_size_when_outer_is_wider() {
181         assert_eq!(
182             Size::get_largest_inner_rect_size(
183                 /* original_size */ &size2(1600, 900),
184                 /* expected_aspect_ratio */ 0.5
185             ),
186             size2(450, 900)
187         );
188     }
189 
190     #[test]
largest_inner_rect_size_when_outer_is_taller()191     fn largest_inner_rect_size_when_outer_is_taller() {
192         assert_eq!(
193             Size::get_largest_inner_rect_size(
194                 /* original_size */ &size2(900, 1600),
195                 /* expected_aspect_ratio */ 3.0
196             ),
197             size2(900, 300)
198         );
199     }
200 }
201