From e2806a6337fe4387934d11b8851121123ca2740a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 22 Oct 2024 11:11:29 +0200 Subject: [PATCH] fractional-scale: implement accurate rounding --- src/renderer/renderer_base.rs | 10 ++++------ src/scale.rs | 13 ++++++------- src/tree/toplevel.rs | 3 ++- src/utils.rs | 1 + src/utils/array_to_tuple.rs | 28 ++++++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 src/utils/array_to_tuple.rs diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index b61af34a..2c983c92 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -30,8 +30,7 @@ impl RendererBase<'_> { pub fn scale_point(&self, mut x: i32, mut y: i32) -> (i32, i32) { if self.scaled { - x = (x as f64 * self.scalef).round() as _; - y = (y as f64 * self.scalef).round() as _; + [x, y] = self.scale.pixel_size([x, y]); } (x, y) } @@ -46,10 +45,9 @@ impl RendererBase<'_> { pub fn scale_rect(&self, mut rect: Rect) -> Rect { if self.scaled { - let x1 = (rect.x1() as f64 * self.scalef).round() as _; - let y1 = (rect.y1() as f64 * self.scalef).round() as _; - let x2 = (rect.x2() as f64 * self.scalef).round() as _; - let y2 = (rect.y2() as f64 * self.scalef).round() as _; + let [x1, y1, x2, y2] = + self.scale + .pixel_size([rect.x1(), rect.y1(), rect.x2(), rect.y2()]); rect = Rect::new(x1, y1, x2, y2).unwrap(); } rect diff --git a/src/scale.rs b/src/scale.rs index ff9835fd..b937faa4 100644 --- a/src/scale.rs +++ b/src/scale.rs @@ -1,6 +1,7 @@ use std::fmt::{Debug, Display, Formatter}; const BASE: u32 = 120; +const BASE64: i64 = BASE as i64; const BASEF: f64 = BASE as f64; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -38,15 +39,13 @@ impl Scale { self.0 } - pub fn pixel_size(self, width: i32, height: i32) -> (i32, i32) { + #[inline(always)] + pub fn pixel_size(self, v: [i32; N]) -> [i32; N] { if self == Scale::default() { - return (width, height); + return v; } - let scale = self.to_f64(); - ( - (width as f64 * scale).round() as i32, - (height as f64 * scale).round() as i32, - ) + let scale = self.0 as i64; + v.map(|v| ((v as i64 * scale + BASE64 / 2) / BASE64) as i32) } } diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 05730aaf..78c65a1f 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -17,6 +17,7 @@ use { PlaceholderNode, WorkspaceNode, }, utils::{ + array_to_tuple::ArrayToTuple, clonecell::CloneCell, copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, @@ -608,7 +609,7 @@ impl ToplevelData { let (dw, dh) = self.desired_extents.get().size(); if let Some(ws) = self.workspace.get() { let scale = ws.output.get().global.persistent.scale.get(); - return scale.pixel_size(dw, dh); + return scale.pixel_size([dw, dh]).to_tuple(); }; (0, 0) } diff --git a/src/utils.rs b/src/utils.rs index d60be29e..ad8e207d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ pub mod activation_token; pub mod array; +pub mod array_to_tuple; pub mod asyncevent; pub mod bindings; pub mod bitfield; diff --git a/src/utils/array_to_tuple.rs b/src/utils/array_to_tuple.rs new file mode 100644 index 00000000..22dc5232 --- /dev/null +++ b/src/utils/array_to_tuple.rs @@ -0,0 +1,28 @@ +pub trait ArrayToTuple { + type Tuple; + + fn to_tuple(self) -> Self::Tuple; +} + +macro_rules! ignore { + ($t:tt) => { + T + }; +} + +macro_rules! array_to_tuple { + ($n:expr, $($field:ident,)*) => { + impl ArrayToTuple for [T; $n] { + type Tuple = ($(ignore!($field),)*); + + fn to_tuple(self) -> Self::Tuple { + let [$($field,)*] = self; + #[allow(clippy::allow_attributes)] + #[allow(clippy::unused_unit)] + ($($field,)*) + } + } + }; +} + +array_to_tuple!(2, t1, t2,);