diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index cb03ac5..4ad9340 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -7,9 +7,11 @@ use image::{ImageBuffer, Rgba}; use slog::Logger; #[cfg(feature = "image")] use smithay::backend::renderer::gles2::{Gles2Error, Gles2Renderer, Gles2Texture}; +#[cfg(feature = "debug")] +use smithay::utils::Transform; use smithay::{ backend::{ - renderer::{buffer_type, BufferType, Frame, ImportAll, Renderer, Texture, Transform}, + renderer::{buffer_type, BufferType, Frame, ImportAll, Renderer, Texture}, SwapBuffersError, }, reexports::wayland_server::protocol::{wl_buffer, wl_surface}, @@ -111,7 +113,11 @@ where .map(|dmg| match dmg { Damage::Buffer(rect) => *rect, // TODO also apply transformations - Damage::Surface(rect) => rect.to_buffer(attributes.buffer_scale), + Damage::Surface(rect) => rect.to_buffer( + attributes.buffer_scale, + attributes.buffer_transform.into(), + &data.size().unwrap(), + ), }) .collect::>(); @@ -161,6 +167,7 @@ where if let Some(data) = states.data_map.get::>() { let mut data = data.borrow_mut(); let buffer_scale = data.buffer_scale; + let buffer_transform = data.buffer_transform; if let Some(texture) = data .texture .as_mut() @@ -177,7 +184,7 @@ where location.to_f64().to_physical(output_scale as f64).to_i32_round(), buffer_scale, output_scale as f64, - Transform::Normal, /* TODO */ + buffer_transform, &[Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))], 1.0, ) { diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 51c2d0d..d295d4f 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -13,7 +13,7 @@ use smithay::{ Display, }, }, - utils::{Logical, Physical, Point, Rectangle, Size}, + utils::{Buffer, Logical, Point, Rectangle, Size, Transform}, wayland::{ compositor::{ compositor_init, is_sync_subsurface, with_states, with_surface_tree_upward, BufferAssignment, @@ -947,8 +947,9 @@ pub struct SurfaceData { pub texture: Option>, pub geometry: Option>, pub resize_state: ResizeState, - pub buffer_dimensions: Option>, + pub buffer_dimensions: Option>, pub buffer_scale: i32, + pub buffer_transform: Transform, } impl SurfaceData { @@ -958,6 +959,7 @@ impl SurfaceData { // new contents self.buffer_dimensions = buffer_dimensions(&buffer); self.buffer_scale = attrs.buffer_scale; + self.buffer_transform = attrs.buffer_transform.into(); if let Some(old_buffer) = std::mem::replace(&mut self.buffer, Some(buffer)) { old_buffer.release(); } @@ -976,7 +978,7 @@ impl SurfaceData { /// Returns the size of the surface. pub fn size(&self) -> Option> { self.buffer_dimensions - .map(|dims| dims.to_logical(self.buffer_scale)) + .map(|dims| dims.to_logical(self.buffer_scale, self.buffer_transform)) } /// Checks if the surface's input region contains the point. diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 9987d32..3b4d3ef 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -20,7 +20,7 @@ use smithay::{ libinput::{LibinputInputBackend, LibinputSessionInterface}, renderer::{ gles2::{Gles2Renderer, Gles2Texture}, - Bind, Frame, Renderer, Transform, + Bind, Frame, Renderer, }, session::{auto::AutoSession, Session, Signal as SessionSignal}, udev::{UdevBackend, UdevEvent}, @@ -50,7 +50,7 @@ use smithay::{ }, utils::{ signaling::{Linkable, SignalToken, Signaler}, - Logical, Point, Rectangle, + Logical, Point, Rectangle, Transform, }, wayland::{ output::{Mode, PhysicalProperties}, diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 2552e04..429e9c1 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -9,7 +9,7 @@ use smithay::{ }; use smithay::{ backend::{ - renderer::{Renderer, Transform}, + renderer::Renderer, winit::{self, WinitEvent}, SwapBuffersError, }, @@ -17,6 +17,7 @@ use smithay::{ calloop::EventLoop, wayland_server::{protocol::wl_output, Display}, }, + utils::Transform, wayland::{ output::{Mode, PhysicalProperties}, seat::CursorImageStatus, diff --git a/anvil/src/x11.rs b/anvil/src/x11.rs index 69766c8..e40d302 100644 --- a/anvil/src/x11.rs +++ b/anvil/src/x11.rs @@ -11,7 +11,7 @@ use smithay::{backend::renderer::ImportDma, wayland::dmabuf::init_dmabuf_global} use smithay::{ backend::{ egl::{EGLContext, EGLDisplay}, - renderer::{gles2::Gles2Renderer, Bind, ImportEgl, Renderer, Transform, Unbind}, + renderer::{gles2::Gles2Renderer, Bind, ImportEgl, Renderer, Unbind}, x11::{WindowBuilder, X11Backend, X11Event, X11Surface}, SwapBuffersError, }, @@ -20,6 +20,7 @@ use smithay::{ gbm, wayland_server::{protocol::wl_output, Display}, }, + utils::Transform, wayland::{ output::{Mode, PhysicalProperties}, seat::CursorImageStatus, diff --git a/src/backend/egl/display.rs b/src/backend/egl/display.rs index da5a37d..1cf3e86 100644 --- a/src/backend/egl/display.rs +++ b/src/backend/egl/display.rs @@ -839,7 +839,7 @@ impl EGLBufferReader { pub fn egl_buffer_dimensions( &self, buffer: &WlBuffer, - ) -> Option> { + ) -> Option> { if !buffer.as_ref().is_alive() { debug!(self.logger, "Suplied buffer is no longer alive"); return None; diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index adad36f..7026569 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -13,7 +13,7 @@ use cgmath::{prelude::*, Matrix3, Vector2, Vector3}; mod shaders; mod version; -use super::{Bind, Frame, Renderer, Texture, TextureFilter, Transform, Unbind}; +use super::{Bind, Frame, Renderer, Texture, TextureFilter, Unbind}; use crate::backend::allocator::{ dmabuf::{Dmabuf, WeakDmabuf}, Format, @@ -23,7 +23,7 @@ use crate::backend::egl::{ EGLContext, EGLSurface, MakeCurrentError, }; use crate::backend::SwapBuffersError; -use crate::utils::{Buffer, Physical, Rectangle, Size}; +use crate::utils::{Buffer, Physical, Rectangle, Size, Transform}; #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use super::ImportEgl; @@ -1250,7 +1250,7 @@ impl Frame for Gles2Frame { texture: &Self::TextureId, src: Rectangle, dest: Rectangle, - damage: &[Rectangle], + damage: &[Rectangle], transform: Transform, alpha: f32, ) -> Result<(), Self::Error> { @@ -1266,7 +1266,7 @@ impl Frame for Gles2Frame { assert_eq!(mat, mat * transform.invert().matrix()); assert_eq!(transform.matrix(), Matrix3::::identity()); } - mat = mat * transform.invert().matrix(); + mat = mat * transform.matrix(); mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5)); // this matrix should be regular, we can expect invert to succeed @@ -1290,18 +1290,24 @@ impl Frame for Gles2Frame { let damage = damage .iter() .map(|rect| { + let src = src.size.to_f64(); let rect = rect.to_f64(); let rect_constrained_loc = rect .loc - .constrain(Rectangle::from_extemities((0f64, 0f64), dest.size.to_point())); - let rect_clamped_size = rect.size.clamp((0f64, 0f64), dest.size); + .constrain(Rectangle::from_extemities((0f64, 0f64), src.to_point())); + let rect_clamped_size = rect + .size + .clamp((0f64, 0f64), (src.to_point() - rect_constrained_loc).to_size()); + + let rect = Rectangle::from_loc_and_size(rect_constrained_loc, rect_clamped_size); + let rect_transformed = self.transformation().transform_rect_in(rect, &src); [ - (rect_constrained_loc.x / dest.size.w) as f32, - (rect_constrained_loc.y / dest.size.h) as f32, - (rect_clamped_size.w / dest.size.w) as f32, - (rect_clamped_size.h / dest.size.h) as f32, + (rect_transformed.loc.x / src.w) as f32, + (rect_transformed.loc.y / src.h) as f32, + (rect_transformed.size.w / src.w) as f32, + (rect_transformed.size.h / src.h) as f32, ] }) .flatten() diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index b624697..39c8f91 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -10,7 +10,7 @@ use std::collections::HashSet; use std::error::Error; -use crate::utils::{Buffer, Coordinate, Physical, Point, Rectangle, Size}; +use crate::utils::{Buffer, Physical, Point, Rectangle, Size, Transform}; #[cfg(feature = "wayland_frontend")] use crate::wayland::compositor::SurfaceData; @@ -35,27 +35,6 @@ use crate::backend::egl::{ #[cfg(feature = "wayland_frontend")] pub mod utils; -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -/// Possible transformations to two-dimensional planes -pub enum Transform { - /// Identity transformation (plane is unaltered when applied) - Normal, - /// Plane is rotated by 90 degrees - _90, - /// Plane is rotated by 180 degrees - _180, - /// Plane is rotated by 270 degrees - _270, - /// Plane is flipped vertically - Flipped, - /// Plane is flipped vertically and rotated by 90 degrees - Flipped90, - /// Plane is flipped vertically and rotated by 180 degrees - Flipped180, - /// Plane is flipped vertically and rotated by 270 degrees - Flipped270, -} - #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] /// Texture filtering methods pub enum TextureFilter { @@ -74,70 +53,11 @@ impl Transform { Transform::_180 => Matrix3::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0), Transform::_270 => Matrix3::new(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0), Transform::Flipped => Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0), - Transform::Flipped90 => Matrix3::new(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0), + Transform::Flipped90 => Matrix3::new(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0), Transform::Flipped180 => Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0), - Transform::Flipped270 => Matrix3::new(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0), + Transform::Flipped270 => Matrix3::new(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0), } } - - /// Inverts any 90-degree transformation into 270-degree transformations and vise versa. - /// - /// Flipping is preserved and 180/Normal transformation are uneffected. - pub fn invert(&self) -> Transform { - match self { - Transform::Normal => Transform::Normal, - Transform::Flipped => Transform::Flipped, - Transform::_90 => Transform::_270, - Transform::_180 => Transform::_180, - Transform::_270 => Transform::_90, - Transform::Flipped90 => Transform::Flipped270, - Transform::Flipped180 => Transform::Flipped180, - Transform::Flipped270 => Transform::Flipped90, - } - } - - /// Transformed size after applying this transformation. - pub fn transform_size(&self, size: Size) -> Size { - if *self == Transform::_90 - || *self == Transform::_270 - || *self == Transform::Flipped90 - || *self == Transform::Flipped270 - { - (size.h, size.w).into() - } else { - size - } - } - - /// Transforms a rectangle inside an area of a given size by applying this transformation - pub fn transform_rect_in( - &self, - rect: Rectangle, - area: &Size, - ) -> Rectangle { - let size = self.transform_size(rect.size); - - let loc = match *self { - Transform::Normal => rect.loc, - Transform::_90 => (area.h - rect.loc.y - rect.size.h, rect.loc.x).into(), - Transform::_180 => ( - area.w - rect.loc.x - rect.size.w, - area.h - rect.loc.y - rect.size.h, - ) - .into(), - Transform::_270 => (rect.loc.y, area.w - rect.loc.x - rect.size.w).into(), - Transform::Flipped => (area.w - rect.loc.x - rect.size.w, rect.loc.y).into(), - Transform::Flipped90 => (rect.loc.y, rect.loc.x).into(), - Transform::Flipped180 => (rect.loc.x, area.h - rect.loc.y - rect.size.h).into(), - Transform::Flipped270 => ( - area.h - rect.loc.y - rect.size.h, - area.w - rect.loc.x - rect.size.w, - ) - .into(), - }; - - Rectangle::from_loc_and_size(loc, size) - } } #[cfg(feature = "wayland_frontend")] @@ -217,7 +137,7 @@ pub trait Frame { texture_scale: i32, output_scale: f64, src_transform: Transform, - damage: &[Rectangle], + damage: &[Rectangle], alpha: f32, ) -> Result<(), Self::Error> { self.render_texture_from_to( @@ -227,7 +147,7 @@ pub trait Frame { pos, texture .size() - .to_logical(texture_scale) + .to_logical(texture_scale, src_transform) .to_f64() .to_physical(output_scale), ), @@ -245,7 +165,7 @@ pub trait Frame { texture: &Self::TextureId, src: Rectangle, dst: Rectangle, - damage: &[Rectangle], + damage: &[Rectangle], src_transform: Transform, alpha: f32, ) -> Result<(), Self::Error>; @@ -540,7 +460,7 @@ pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option { /// /// *Note*: This will only return dimensions for buffer types known to smithay (see [`buffer_type`]) #[cfg(feature = "wayland_frontend")] -pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option> { +pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option> { use crate::backend::allocator::Buffer; if let Some(buf) = buffer.as_ref().user_data().get::() { @@ -560,102 +480,3 @@ pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::Normal; - - assert_eq!(rect, transform.transform_rect_in(rect, &size)) - } - - #[test] - fn transform_rect_90() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::_90; - - assert_eq!( - Rectangle::from_loc_and_size((30, 10), (40, 30)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_180() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::_180; - - assert_eq!( - Rectangle::from_loc_and_size((30, 30), (30, 40)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_270() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::_270; - - assert_eq!( - Rectangle::from_loc_and_size((20, 30), (40, 30)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_f() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::Flipped; - - assert_eq!( - Rectangle::from_loc_and_size((30, 20), (30, 40)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_f90() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 80)); - let transform = Transform::Flipped90; - - assert_eq!( - Rectangle::from_loc_and_size((20, 10), (40, 30)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_f180() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::Flipped180; - - assert_eq!( - Rectangle::from_loc_and_size((10, 30), (30, 40)), - transform.transform_rect_in(rect, &size) - ) - } - - #[test] - fn transform_rect_f270() { - let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); - let size = Size::from((70, 90)); - let transform = Transform::Flipped270; - - assert_eq!( - Rectangle::from_loc_and_size((30, 30), (40, 30)), - transform.transform_rect_in(rect, &size) - ) - } -} diff --git a/src/backend/renderer/utils.rs b/src/backend/renderer/utils.rs index 1b38f01..e267916 100644 --- a/src/backend/renderer/utils.rs +++ b/src/backend/renderer/utils.rs @@ -2,7 +2,7 @@ use crate::{ backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture}, - utils::{Logical, Physical, Point, Rectangle, Size}, + utils::{Buffer, Logical, Point, Rectangle, Size, Transform}, wayland::compositor::{ is_sync_subsurface, with_surface_tree_upward, BufferAssignment, Damage, SubsurfaceCachedState, SurfaceAttributes, TraversalAction, @@ -15,8 +15,9 @@ use wayland_server::protocol::{wl_buffer::WlBuffer, wl_surface::WlSurface}; #[derive(Default)] pub(crate) struct SurfaceState { - pub(crate) buffer_dimensions: Option>, + pub(crate) buffer_dimensions: Option>, pub(crate) buffer_scale: i32, + pub(crate) buffer_transform: Transform, pub(crate) buffer: Option, pub(crate) texture: Option>, #[cfg(feature = "desktop")] @@ -30,6 +31,7 @@ impl SurfaceState { // new contents self.buffer_dimensions = buffer_dimensions(&buffer); self.buffer_scale = attrs.buffer_scale; + self.buffer_transform = attrs.buffer_transform.into(); if let Some(old_buffer) = std::mem::replace(&mut self.buffer, Some(buffer)) { if &old_buffer != self.buffer.as_ref().unwrap() { old_buffer.release(); @@ -52,6 +54,13 @@ impl SurfaceState { None => {} } } + + /// Returns the size of the surface. + pub fn surface_size(&self) -> Option> { + self.buffer_dimensions + .as_ref() + .map(|dim| dim.to_logical(self.buffer_scale, self.buffer_transform)) + } } /// Handler to let smithay take over buffer management. @@ -110,10 +119,6 @@ where T: Texture + 'static, { let mut result = Ok(()); - let damage = damage - .iter() - .map(|geo| geo.to_f64().to_physical(scale).to_i32_up()) - .collect::>(); with_surface_tree_upward( surface, location, @@ -125,17 +130,20 @@ where // Import a new buffer if necessary if data.texture.is_none() { if let Some(buffer) = data.buffer.as_ref() { - let damage = attributes + let buffer_damage = attributes .damage .iter() .map(|dmg| match dmg { Damage::Buffer(rect) => *rect, - // TODO also apply transformations - Damage::Surface(rect) => rect.to_buffer(attributes.buffer_scale), + Damage::Surface(rect) => rect.to_buffer( + attributes.buffer_scale, + attributes.buffer_transform.into(), + &data.surface_size().unwrap(), + ), }) .collect::>(); - match renderer.import_buffer(buffer, Some(states), &damage) { + match renderer.import_buffer(buffer, Some(states), &buffer_damage) { Some(Ok(m)) => { data.texture = Some(Box::new(m)); } @@ -169,10 +177,12 @@ where let mut location = *location; if let Some(data) = states.data_map.get::>() { let mut data = data.borrow_mut(); + let dimensions = data.surface_size(); let buffer_scale = data.buffer_scale; - let buffer_dimensions = data.buffer_dimensions; + let buffer_transform = data.buffer_transform; let attributes = states.cached_state.current::(); if let Some(texture) = data.texture.as_mut().and_then(|x| x.downcast_mut::()) { + let dimensions = dimensions.unwrap(); // we need to re-extract the subsurface offset, as the previous closure // only passes it to our children let mut surface_offset = (0, 0).into(); @@ -182,23 +192,19 @@ where location += current.location; } - let rect = Rectangle::::from_loc_and_size( - surface_offset.to_f64().to_physical(scale).to_i32_round(), - buffer_dimensions - .unwrap_or_default() - .to_logical(buffer_scale) - .to_f64() - .to_physical(scale) - .to_i32_round(), - ); - let new_damage = damage + let damage = damage .iter() .cloned() - .flat_map(|geo| geo.intersection(rect)) + // first move the damage by the surface offset in logical space .map(|mut geo| { - geo.loc -= rect.loc; + // make the damage relative to the surfaec + geo.loc -= surface_offset; geo }) + // then clamp to surface size again in logical space + .flat_map(|geo| geo.intersection(Rectangle::from_loc_and_size((0, 0), dimensions))) + // lastly transform it into buffer space + .map(|geo| geo.to_buffer(buffer_scale, buffer_transform, &dimensions)) .collect::>(); // TODO: Take wp_viewporter into account @@ -208,7 +214,7 @@ where buffer_scale, scale, attributes.buffer_transform.into(), - &new_damage, + &damage, 1.0, ) { result = Err(err); diff --git a/src/desktop/space/mod.rs b/src/desktop/space/mod.rs index 7f49392..56b1119 100644 --- a/src/desktop/space/mod.rs +++ b/src/desktop/space/mod.rs @@ -2,12 +2,12 @@ //! rendering helpers to add custom elements or different clients to a space. use crate::{ - backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform}, + backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer}, desktop::{ layer::{layer_map_for_output, LayerSurface}, window::Window, }, - utils::{Logical, Point, Rectangle}, + utils::{Logical, Point, Rectangle, Transform}, wayland::{ compositor::{ get_parent, is_sync_subsurface, with_surface_tree_downward, SubsurfaceCachedState, @@ -372,7 +372,7 @@ impl Space { |wl_surface, states, &loc| { let data = states.data_map.get::>(); - if let Some(size) = data.and_then(|d| d.borrow().size()) { + if let Some(size) = data.and_then(|d| d.borrow().surface_size()) { let surface_rectangle = Rectangle { loc, size }; if output_geometry.overlaps(surface_rectangle) { diff --git a/src/desktop/utils.rs b/src/desktop/utils.rs index 380ae4e..b855691 100644 --- a/src/desktop/utils.rs +++ b/src/desktop/utils.rs @@ -3,7 +3,7 @@ use crate::{ backend::renderer::utils::SurfaceState, desktop::Space, - utils::{Logical, Point, Rectangle, Size}, + utils::{Logical, Point, Rectangle}, wayland::{ compositor::{ with_surface_tree_downward, with_surface_tree_upward, Damage, SubsurfaceCachedState, @@ -17,15 +17,9 @@ use wayland_server::protocol::wl_surface; use std::cell::RefCell; impl SurfaceState { - /// Returns the size of the surface. - pub fn size(&self) -> Option> { - self.buffer_dimensions - .map(|dims| dims.to_logical(self.buffer_scale)) - } - fn contains_point>>(&self, attrs: &SurfaceAttributes, point: P) -> bool { let point = point.into(); - let size = match self.size() { + let size = match self.surface_size() { None => return false, // If the surface has no size, it can't have an input region. Some(size) => size, }; @@ -71,7 +65,7 @@ where let mut loc = *loc; let data = states.data_map.get::>(); - if let Some(size) = data.and_then(|d| d.borrow().size()) { + if let Some(size) = data.and_then(|d| d.borrow().surface_size()) { if states.role == Some("subsurface") { let current = states.cached_state.current::(); loc += current.location; @@ -148,7 +142,11 @@ where damage.extend(attributes.damage.iter().map(|dmg| { let mut rect = match dmg { - Damage::Buffer(rect) => rect.to_logical(attributes.buffer_scale), + Damage::Buffer(rect) => rect.to_logical( + attributes.buffer_scale, + attributes.buffer_transform.into(), + &data.buffer_dimensions.unwrap(), + ), Damage::Surface(rect) => *rect, }; rect.loc += location; diff --git a/src/utils/geometry.rs b/src/utils/geometry.rs index b4a14a3..98c2848 100644 --- a/src/utils/geometry.rs +++ b/src/utils/geometry.rs @@ -406,10 +406,11 @@ impl Point { #[inline] /// Convert this logical point to buffer coordinate space according to given scale factor - pub fn to_buffer(self, scale: N) -> Point { + pub fn to_buffer(self, scale: N, transformation: Transform, area: &Size) -> Point { + let point = transformation.transform_point_in(self, area); Point { - x: self.x.upscale(scale), - y: self.y.upscale(scale), + x: point.x.upscale(scale), + y: point.y.upscale(scale), _kind: std::marker::PhantomData, } } @@ -430,10 +431,11 @@ impl Point { impl Point { #[inline] /// Convert this physical point to logical coordinate space according to given scale factor - pub fn to_logical(self, scale: N) -> Point { + pub fn to_logical(self, scale: N, transform: Transform, area: &Size) -> Point { + let point = transform.invert().transform_point_in(self, area); Point { - x: self.x.downscale(scale), - y: self.y.downscale(scale), + x: point.x.downscale(scale), + y: point.y.downscale(scale), _kind: std::marker::PhantomData, } } @@ -667,12 +669,12 @@ impl Size { #[inline] /// Convert this logical size to buffer coordinate space according to given scale factor - pub fn to_buffer(self, scale: N) -> Size { - Size { + pub fn to_buffer(self, scale: N, transformation: Transform) -> Size { + transformation.transform_size(Size { w: self.w.upscale(scale), h: self.h.upscale(scale), _kind: std::marker::PhantomData, - } + }) } } @@ -691,12 +693,12 @@ impl Size { impl Size { #[inline] /// Convert this physical point to logical coordinate space according to given scale factor - pub fn to_logical(self, scale: N) -> Size { - Size { + pub fn to_logical(self, scale: N, transformation: Transform) -> Size { + transformation.invert().transform_size(Size { w: self.w.downscale(scale), h: self.h.downscale(scale), _kind: std::marker::PhantomData, - } + }) } } @@ -969,10 +971,24 @@ impl Rectangle { /// Convert this logical rectangle to buffer coordinate space according to given scale factor #[inline] - pub fn to_buffer(self, scale: N) -> Rectangle { + pub fn to_buffer( + self, + scale: N, + transformation: Transform, + area: &Size, + ) -> Rectangle { + let rect = transformation.transform_rect_in(self, area); Rectangle { - loc: self.loc.to_buffer(scale), - size: self.size.to_buffer(scale), + loc: Point { + x: rect.loc.x.upscale(scale), + y: rect.loc.y.upscale(scale), + _kind: std::marker::PhantomData, + }, + size: Size { + w: rect.size.w.upscale(scale), + h: rect.size.h.upscale(scale), + _kind: std::marker::PhantomData, + }, } } } @@ -991,10 +1007,24 @@ impl Rectangle { impl Rectangle { /// Convert this physical rectangle to logical coordinate space according to given scale factor #[inline] - pub fn to_logical(self, scale: N) -> Rectangle { + pub fn to_logical( + self, + scale: N, + transformation: Transform, + area: &Size, + ) -> Rectangle { + let rect = transformation.invert().transform_rect_in(self, area); Rectangle { - loc: self.loc.to_logical(scale), - size: self.size.to_logical(scale), + loc: Point { + x: rect.loc.x.downscale(scale), + y: rect.loc.y.downscale(scale), + _kind: std::marker::PhantomData, + }, + size: Size { + w: rect.size.w.downscale(scale), + h: rect.size.h.downscale(scale), + _kind: std::marker::PhantomData, + }, } } } @@ -1071,3 +1101,207 @@ impl Default for Rectangle { } } } + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +/// Possible transformations to two-dimensional planes +pub enum Transform { + /// Identity transformation (plane is unaltered when applied) + Normal, + /// Plane is rotated by 90 degrees + _90, + /// Plane is rotated by 180 degrees + _180, + /// Plane is rotated by 270 degrees + _270, + /// Plane is flipped vertically + Flipped, + /// Plane is flipped vertically and rotated by 90 degrees + Flipped90, + /// Plane is flipped vertically and rotated by 180 degrees + Flipped180, + /// Plane is flipped vertically and rotated by 270 degrees + Flipped270, +} + +impl Default for Transform { + fn default() -> Transform { + Transform::Normal + } +} + +impl Transform { + /// Inverts any 90-degree transformation into 270-degree transformations and vise versa. + /// + /// Flipping is preserved and 180/Normal transformation are uneffected. + pub fn invert(&self) -> Transform { + match self { + Transform::Normal => Transform::Normal, + Transform::Flipped => Transform::Flipped, + Transform::_90 => Transform::_270, + Transform::_180 => Transform::_180, + Transform::_270 => Transform::_90, + Transform::Flipped90 => Transform::Flipped270, + Transform::Flipped180 => Transform::Flipped180, + Transform::Flipped270 => Transform::Flipped90, + } + } + + /// Transforms a point inside an area of a given size by applying this transformation. + pub fn transform_point_in( + &self, + point: Point, + area: &Size, + ) -> Point { + match *self { + Transform::Normal => point, + Transform::_90 => (area.h - point.y, point.x).into(), + Transform::_180 => (area.w - point.x, area.h - point.y).into(), + Transform::_270 => (point.y, area.w - point.x).into(), + Transform::Flipped => (area.w - point.x, point.y).into(), + Transform::Flipped90 => (point.y, point.x).into(), + Transform::Flipped180 => (point.x, area.h - point.y).into(), + Transform::Flipped270 => (area.h - point.y, area.w - point.x).into(), + } + } + + /// Transformed size after applying this transformation. + pub fn transform_size(&self, size: Size) -> Size { + if *self == Transform::_90 + || *self == Transform::_270 + || *self == Transform::Flipped90 + || *self == Transform::Flipped270 + { + (size.h, size.w).into() + } else { + size + } + } + + /// Transforms a rectangle inside an area of a given size by applying this transformation. + pub fn transform_rect_in( + &self, + rect: Rectangle, + area: &Size, + ) -> Rectangle { + let size = self.transform_size(rect.size); + + let loc = match *self { + Transform::Normal => rect.loc, + Transform::_90 => (area.h - rect.loc.y - rect.size.h, rect.loc.x).into(), + Transform::_180 => ( + area.w - rect.loc.x - rect.size.w, + area.h - rect.loc.y - rect.size.h, + ) + .into(), + Transform::_270 => (rect.loc.y, area.w - rect.loc.x - rect.size.w).into(), + Transform::Flipped => (area.w - rect.loc.x - rect.size.w, rect.loc.y).into(), + Transform::Flipped90 => (rect.loc.y, rect.loc.x).into(), + Transform::Flipped180 => (rect.loc.x, area.h - rect.loc.y - rect.size.h).into(), + Transform::Flipped270 => ( + area.h - rect.loc.y - rect.size.h, + area.w - rect.loc.x - rect.size.w, + ) + .into(), + }; + + Rectangle::from_loc_and_size(loc, size) + } +} + +#[cfg(test)] +mod tests { + use super::{Logical, Rectangle, Size, Transform}; + + #[test] + fn transform_rect_ident() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::Normal; + + assert_eq!(rect, transform.transform_rect_in(rect, &size)) + } + + #[test] + fn transform_rect_90() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::_90; + + assert_eq!( + Rectangle::from_loc_and_size((30, 10), (40, 30)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_180() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::_180; + + assert_eq!( + Rectangle::from_loc_and_size((30, 30), (30, 40)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_270() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::_270; + + assert_eq!( + Rectangle::from_loc_and_size((20, 30), (40, 30)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_f() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::Flipped; + + assert_eq!( + Rectangle::from_loc_and_size((30, 20), (30, 40)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_f90() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 80)); + let transform = Transform::Flipped90; + + assert_eq!( + Rectangle::from_loc_and_size((20, 10), (40, 30)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_f180() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::Flipped180; + + assert_eq!( + Rectangle::from_loc_and_size((10, 30), (30, 40)), + transform.transform_rect_in(rect, &size) + ) + } + + #[test] + fn transform_rect_f270() { + let rect = Rectangle::::from_loc_and_size((10, 20), (30, 40)); + let size = Size::from((70, 90)); + let transform = Transform::Flipped270; + + assert_eq!( + Rectangle::from_loc_and_size((30, 30), (40, 30)), + transform.transform_rect_in(rect, &size) + ) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index de3d678..bbe8e55 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -10,7 +10,7 @@ pub mod x11rb; pub(crate) mod ids; pub mod user_data; -pub use self::geometry::{Buffer, Coordinate, Logical, Physical, Point, Raw, Rectangle, Size}; +pub use self::geometry::{Buffer, Coordinate, Logical, Physical, Point, Raw, Rectangle, Size, Transform}; /// This resource is not managed by Smithay #[derive(Debug)] diff --git a/wlcs_anvil/src/main_loop.rs b/wlcs_anvil/src/main_loop.rs index cc1108e..2b5ad8d 100644 --- a/wlcs_anvil/src/main_loop.rs +++ b/wlcs_anvil/src/main_loop.rs @@ -5,7 +5,7 @@ use std::{ use smithay::{ backend::{ - renderer::{Frame, Renderer, Transform}, + renderer::{Frame, Renderer}, SwapBuffersError, }, reexports::{ @@ -18,7 +18,7 @@ use smithay::{ Client, Display, }, }, - utils::Rectangle, + utils::{Rectangle, Transform}, wayland::{ output::{Mode, PhysicalProperties}, seat::CursorImageStatus, diff --git a/wlcs_anvil/src/renderer.rs b/wlcs_anvil/src/renderer.rs index bd75ec1..6454d7d 100644 --- a/wlcs_anvil/src/renderer.rs +++ b/wlcs_anvil/src/renderer.rs @@ -3,11 +3,11 @@ use std::cell::Cell; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, - renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, TextureFilter, Transform}, + renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, TextureFilter}, SwapBuffersError, }, reexports::wayland_server::protocol::wl_buffer, - utils::{Buffer, Physical, Rectangle, Size}, + utils::{Buffer, Physical, Rectangle, Size, Transform}, wayland::compositor::SurfaceData, }; @@ -106,7 +106,7 @@ impl Frame for DummyFrame { _texture: &Self::TextureId, _src: Rectangle, _dst: Rectangle, - _damage: &[Rectangle], + _damage: &[Rectangle], _src_transform: Transform, _alpha: f32, ) -> Result<(), Self::Error> {