use crate::Size;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ScaleFactor(f64);
impl ScaleFactor {
pub const IDENTITY: Self = Self(1.0);
#[inline]
pub fn new(factor: f64) -> Self {
if factor.is_finite() && factor > 0.0 {
Self(factor)
} else {
Self::IDENTITY
}
}
#[inline]
pub fn get(self) -> f64 {
self.0
}
#[inline]
pub fn to_physical(self, logical: Size) -> PhysicalSize {
PhysicalSize {
width: (logical.width * self.0).round().max(0.0) as u32,
height: (logical.height * self.0).round().max(0.0) as u32,
}
}
#[inline]
pub fn to_logical(self, physical: PhysicalSize) -> Size {
Size::new(
physical.width as f64 / self.0,
physical.height as f64 / self.0,
)
}
}
impl Default for ScaleFactor {
#[inline]
fn default() -> Self {
Self::IDENTITY
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct PhysicalSize {
pub width: u32,
pub height: u32,
}
impl PhysicalSize {
#[inline]
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
#[inline]
pub const fn pixel_count(self) -> u64 {
self.width as u64 * self.height as u64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hidpi_roundtrip() {
let s = ScaleFactor::new(2.0);
assert_eq!(
s.to_physical(Size::new(100.0, 50.0)),
PhysicalSize::new(200, 100)
);
assert_eq!(
s.to_logical(PhysicalSize::new(200, 100)),
Size::new(100.0, 50.0)
);
}
#[test]
fn invalid_scale_falls_back_to_identity() {
assert_eq!(ScaleFactor::new(0.0), ScaleFactor::IDENTITY);
assert_eq!(ScaleFactor::new(f64::NAN), ScaleFactor::IDENTITY);
assert_eq!(ScaleFactor::new(-1.0), ScaleFactor::IDENTITY);
}
}