From 33f6a4b91472af2c75bcbda9e8d46e2f3a62e6d6 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Wed, 6 Jan 2021 16:42:26 -0800 Subject: [PATCH] Fix dpi scaling (#438) * fixing dpi * refactor rendered window for better dpi scaling * prevent cursor from animating out of the window bounds Co-authored-by: Gabby Grinslade --- src/editor/window.rs | 2 + src/renderer/cursor_renderer/mod.rs | 19 ++- src/renderer/mod.rs | 14 +- src/renderer/rendered_window.rs | 233 ++++++++++++++++------------ src/renderer/utils.rs | 99 ------------ src/window/mod.rs | 1 + src/window/sdl2/mod.rs | 3 +- 7 files changed, 159 insertions(+), 212 deletions(-) delete mode 100644 src/renderer/utils.rs diff --git a/src/editor/window.rs b/src/editor/window.rs index a34f3fd..c9eb181 100644 --- a/src/editor/window.rs +++ b/src/editor/window.rs @@ -166,11 +166,13 @@ impl Window { self.grid_left = grid_left; self.grid_top = grid_top; self.send_updated_position(); + self.redraw(); } pub fn resize(&mut self, width: u64, height: u64) { self.grid.resize(width, height); self.send_updated_position(); + self.redraw(); } fn modify_grid( diff --git a/src/renderer/cursor_renderer/mod.rs b/src/renderer/cursor_renderer/mod.rs index 8814aa3..c78f8ce 100644 --- a/src/renderer/cursor_renderer/mod.rs +++ b/src/renderer/cursor_renderer/mod.rs @@ -247,13 +247,18 @@ impl CursorRenderer { let (cursor_grid_x, cursor_grid_y) = self.cursor.grid_position; if let Some(window) = windows.get(&self.cursor.parent_window_id) { - self.destination = ( - (cursor_grid_x as f32 + window.grid_current_position.x) * font_width, - (cursor_grid_y as f32 + window.grid_current_position.y - - (window.current_scroll - window.current_surfaces.top_line)) - * font_height, - ) - .into(); + let grid_x = cursor_grid_x as f32 + window.grid_current_position.x; + let mut grid_y = cursor_grid_y as f32 + window.grid_current_position.y + - (window.current_scroll - window.current_surfaces.top_line); + + // Prevent the cursor from targeting a position outside its current window. Since only + // the vertical direction is effected by scrolling, we only have to clamp the vertical + // grid position. + grid_y = grid_y + .max(window.grid_current_position.y) + .min(window.grid_current_position.y + window.grid_height as f32 - 1.0); + + self.destination = (grid_x * font_width, grid_y * font_height).into(); } else { self.destination = ( cursor_grid_x as f32 * font_width, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6b65b44..169db7a 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -217,7 +217,12 @@ impl Renderer { canvas.restore(); } - pub fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) { + pub fn handle_draw_command( + &mut self, + root_canvas: &mut Canvas, + draw_command: DrawCommand, + scaling: f32, + ) { warn!("{:?}", &draw_command); match draw_command { DrawCommand::Window { @@ -228,7 +233,8 @@ impl Renderer { } DrawCommand::Window { grid_id, command } => { if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) { - let rendered_window = rendered_window.handle_window_draw_command(self, command); + let rendered_window = + rendered_window.handle_window_draw_command(self, command, scaling); self.rendered_windows.insert(grid_id, rendered_window); } else if let WindowDrawCommand::Position { grid_left, @@ -246,6 +252,7 @@ impl Renderer { (grid_left as f32, grid_top as f32).into(), width, height, + scaling, ); self.rendered_windows.insert(grid_id, new_window); } else { @@ -273,6 +280,7 @@ impl Renderer { root_canvas: &mut Canvas, coordinate_system_helper: &CoordinateSystemHelper, dt: f32, + scaling: f32, ) -> bool { trace!("Rendering"); let mut font_changed = false; @@ -287,7 +295,7 @@ impl Renderer { if let DrawCommand::FontChanged(_) = draw_command { font_changed = true; } - self.handle_draw_command(root_canvas, draw_command); + self.handle_draw_command(root_canvas, draw_command, scaling); } root_canvas.clear( diff --git a/src/renderer/rendered_window.rs b/src/renderer/rendered_window.rs index 5fcec5f..e2b18ea 100644 --- a/src/renderer/rendered_window.rs +++ b/src/renderer/rendered_window.rs @@ -1,10 +1,10 @@ use std::collections::VecDeque; -use std::iter; use skulpin::skia_safe::canvas::{SaveLayerRec, SrcRectConstraint}; use skulpin::skia_safe::gpu::SurfaceOrigin; use skulpin::skia_safe::{ - image_filters::blur, BlendMode, Budgeted, Canvas, Color, ImageInfo, Paint, Point, Rect, Surface, + image_filters::blur, BlendMode, Budgeted, Canvas, Color, Image, ImageInfo, Paint, Point, Rect, + Surface, }; use super::animation_utils::*; @@ -45,9 +45,10 @@ fn build_window_surface_with_grid_size( renderer: &Renderer, grid_width: u64, grid_height: u64, + scaling: f32, ) -> Surface { - let pixel_width = (grid_width as f32 * renderer.font_width) as i32; - let pixel_height = (grid_height as f32 * renderer.font_height) as i32; + let pixel_width = (grid_width as f32 * renderer.font_width / scaling) as i32; + let pixel_height = (grid_height as f32 * renderer.font_height / scaling) as i32; build_window_surface(parent_canvas, pixel_width, pixel_height) } @@ -56,28 +57,30 @@ fn build_background_window_surface( renderer: &Renderer, grid_width: u64, grid_height: u64, + scaling: f32, ) -> Surface { - let mut surface = - build_window_surface_with_grid_size(parent_canvas, renderer, grid_width, grid_height); + let mut surface = build_window_surface_with_grid_size( + parent_canvas, + renderer, + grid_width, + grid_height, + scaling, + ); let canvas = surface.canvas(); canvas.clear(renderer.get_default_background()); surface } -fn clone_window_surface(surface: &mut Surface) -> Surface { - let snapshot = surface.image_snapshot(); - let mut canvas = surface.canvas(); - let mut new_surface = build_window_surface(&mut canvas, snapshot.width(), snapshot.height()); - let new_canvas = new_surface.canvas(); - new_canvas.draw_image(snapshot, (0.0, 0.0), None); - new_surface +pub struct SnapshotPair { + background: Image, + foreground: Image, + top_line: f32, } pub struct SurfacePair { background: Surface, foreground: Surface, pub top_line: f32, - bottom_line: f32, } impl SurfacePair { @@ -87,43 +90,51 @@ impl SurfacePair { grid_width: u64, grid_height: u64, top_line: f32, - bottom_line: f32, + scaling: f32, ) -> SurfacePair { - let background = - build_background_window_surface(parent_canvas, renderer, grid_width, grid_height); - let foreground = - build_window_surface_with_grid_size(parent_canvas, renderer, grid_width, grid_height); + let background = build_background_window_surface( + parent_canvas, + renderer, + grid_width, + grid_height, + scaling, + ); + let foreground = build_window_surface_with_grid_size( + parent_canvas, + renderer, + grid_width, + grid_height, + scaling, + ); SurfacePair { background, foreground, top_line, - bottom_line, } } - fn clone(&mut self) -> SurfacePair { - let new_background = clone_window_surface(&mut self.background); - let new_foreground = clone_window_surface(&mut self.foreground); - SurfacePair { - background: new_background, - foreground: new_foreground, + fn snapshot(&mut self) -> SnapshotPair { + let background = self.background.image_snapshot(); + let foreground = self.foreground.image_snapshot(); + SnapshotPair { + background, + foreground, top_line: self.top_line, - bottom_line: self.bottom_line, } } } pub struct RenderedWindow { - old_surfaces: VecDeque, + snapshots: VecDeque, pub current_surfaces: SurfacePair, pub id: u64, pub hidden: bool, pub floating: bool, - grid_width: u64, - grid_height: u64, + pub grid_width: u64, + pub grid_height: u64, grid_start_position: Point, pub grid_current_position: Point, @@ -150,12 +161,19 @@ impl RenderedWindow { grid_position: Point, grid_width: u64, grid_height: u64, + scaling: f32, ) -> RenderedWindow { - let current_surfaces = - SurfacePair::new(parent_canvas, renderer, grid_width, grid_height, 0.0, 0.0); + let current_surfaces = SurfacePair::new( + parent_canvas, + renderer, + grid_width, + grid_height, + 0.0, + scaling, + ); RenderedWindow { - old_surfaces: VecDeque::new(), + snapshots: VecDeque::new(), current_surfaces, id, hidden: false, @@ -213,7 +231,7 @@ impl RenderedWindow { if (self.scroll_t - 1.0).abs() < std::f32::EPSILON { // We are at destination, move t out of 0-1 range to stop the animation self.scroll_t = 2.0; - self.old_surfaces.clear(); + self.snapshots.clear(); } else { animating = true; self.scroll_t = (self.scroll_t + dt / settings.scroll_animation_length).min(1.0); @@ -275,36 +293,59 @@ impl RenderedWindow { paint.set_color(Color::from_argb(a, 255, 255, 255)); - for surface_pair in iter::once(&mut self.current_surfaces) - .chain(self.old_surfaces.iter_mut()) - .rev() - { + // Draw background scrolling snapshots + for snapshot_pair in self.snapshots.iter_mut().rev() { let scroll_offset = - surface_pair.top_line * font_height - self.current_scroll * font_height; - surface_pair.background.draw( - root_canvas.as_mut(), - (pixel_region.left(), pixel_region.top() + scroll_offset), - Some(&paint), + snapshot_pair.top_line * font_height - self.current_scroll * font_height; + let background_snapshot = &mut snapshot_pair.background; + root_canvas.draw_image_rect( + background_snapshot, + None, + pixel_region.with_offset((0.0, scroll_offset)), + &paint, ); } + // Draw background + let scroll_offset = + self.current_surfaces.top_line * font_height - self.current_scroll * font_height; + let background_snapshot = self.current_surfaces.background.image_snapshot(); + root_canvas.draw_image_rect( + background_snapshot, + None, + pixel_region.with_offset((0.0, scroll_offset)), + &paint, + ); + root_canvas.restore(); } { // Save layer so that text may safely overwrite images underneath root_canvas.save_layer(&SaveLayerRec::default()); - for surface_pair in iter::once(&mut self.current_surfaces) - .chain(self.old_surfaces.iter_mut()) - .rev() - { + + // Draw foreground scrolling snapshots + for snapshot_pair in self.snapshots.iter_mut().rev() { let scroll_offset = - surface_pair.top_line * font_height - self.current_scroll * font_height; - surface_pair.foreground.draw( - root_canvas.as_mut(), - (pixel_region.left(), pixel_region.top() + scroll_offset), - Some(&paint), + snapshot_pair.top_line * font_height - self.current_scroll * font_height; + let foreground_snapshot = &mut snapshot_pair.foreground; + root_canvas.draw_image_rect( + foreground_snapshot, + None, + pixel_region.with_offset((0.0, scroll_offset)), + &paint, ); } + + // Draw foreground + let scroll_offset = + self.current_surfaces.top_line * font_height - self.current_scroll * font_height; + let foreground_snapshot = self.current_surfaces.foreground.image_snapshot(); + root_canvas.draw_image_rect( + foreground_snapshot, + None, + pixel_region.with_offset((0.0, scroll_offset)), + &paint, + ); root_canvas.restore(); } @@ -325,6 +366,7 @@ impl RenderedWindow { mut self, renderer: &mut Renderer, draw_command: WindowDrawCommand, + scaling: f32, ) -> Self { match draw_command { WindowDrawCommand::Position { @@ -360,6 +402,7 @@ impl RenderedWindow { &renderer, grid_width, grid_height, + scaling, ); old_background.draw( self.current_surfaces.background.canvas(), @@ -375,6 +418,7 @@ impl RenderedWindow { &renderer, grid_width, grid_height, + scaling, ); old_foreground.draw( self.current_surfaces.foreground.canvas(), @@ -406,24 +450,19 @@ impl RenderedWindow { let grid_position = (window_left, window_top); { - let mut background_canvas = self.current_surfaces.background.canvas(); - renderer.draw_background( - &mut background_canvas, - grid_position, - cell_width, - &style, - ); + let canvas = self.current_surfaces.background.canvas(); + canvas.save(); + canvas.scale((1.0 / scaling, 1.0 / scaling)); + renderer.draw_background(canvas, grid_position, cell_width, &style); + canvas.restore(); } { - let mut foreground_canvas = self.current_surfaces.foreground.canvas(); - renderer.draw_foreground( - &mut foreground_canvas, - &text, - grid_position, - cell_width, - &style, - ); + let canvas = self.current_surfaces.foreground.canvas(); + canvas.save(); + canvas.scale((1.0 / scaling, 1.0 / scaling)); + renderer.draw_foreground(canvas, &text, grid_position, cell_width, &style); + canvas.restore(); } } WindowDrawCommand::Scroll { @@ -435,12 +474,18 @@ impl RenderedWindow { cols, } => { let scrolled_region = Rect::new( - left as f32 * renderer.font_width, - top as f32 * renderer.font_height, - right as f32 * renderer.font_width, - bot as f32 * renderer.font_height, + left as f32 * renderer.font_width / scaling, + top as f32 * renderer.font_height / scaling, + right as f32 * renderer.font_width / scaling, + bot as f32 * renderer.font_height / scaling, ); + let mut translated_region = scrolled_region; + translated_region.offset(( + -cols as f32 * renderer.font_width / scaling, + -rows as f32 * renderer.font_height / scaling, + )); + { let background_snapshot = self.current_surfaces.background.image_snapshot(); let background_canvas = self.current_surfaces.background.canvas(); @@ -448,12 +493,6 @@ impl RenderedWindow { background_canvas.save(); background_canvas.clip_rect(scrolled_region, None, Some(false)); - let mut translated_region = scrolled_region; - translated_region.offset(( - -cols as f32 * renderer.font_width, - -rows as f32 * renderer.font_height, - )); - background_canvas.draw_image_rect( background_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), @@ -471,12 +510,6 @@ impl RenderedWindow { foreground_canvas.save(); foreground_canvas.clip_rect(scrolled_region, None, Some(false)); - let mut translated_region = scrolled_region; - translated_region.offset(( - -cols as f32 * renderer.font_width, - -rows as f32 * renderer.font_height, - )); - foreground_canvas.draw_image_rect( foreground_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), @@ -488,21 +521,23 @@ impl RenderedWindow { } } WindowDrawCommand::Clear => { - let background_canvas = self.current_surfaces.background.canvas(); self.current_surfaces.background = build_background_window_surface( - background_canvas, + self.current_surfaces.background.canvas(), &renderer, self.grid_width, self.grid_height, + scaling, ); - let foreground_canvas = self.current_surfaces.foreground.canvas(); self.current_surfaces.foreground = build_window_surface_with_grid_size( - foreground_canvas, + self.current_surfaces.foreground.canvas(), &renderer, self.grid_width, self.grid_height, + scaling, ); + + self.snapshots.clear(); } WindowDrawCommand::Show => { if self.hidden { @@ -512,27 +547,21 @@ impl RenderedWindow { } } WindowDrawCommand::Hide => self.hidden = true, - WindowDrawCommand::Viewport { - top_line, - bottom_line, - } => { + WindowDrawCommand::Viewport { top_line, .. } => { if (self.current_surfaces.top_line - top_line as f32).abs() > std::f32::EPSILON { - let mut new_surfaces = self.current_surfaces.clone(); - new_surfaces.top_line = top_line as f32; - new_surfaces.bottom_line = bottom_line as f32; + let new_snapshot = self.current_surfaces.snapshot(); + self.snapshots.push_back(new_snapshot); + + if self.snapshots.len() > 5 { + self.snapshots.pop_front(); + } + + self.current_surfaces.top_line = top_line as f32; // Set new target viewport position and initialize animation timer self.start_scroll = self.current_scroll; self.scroll_destination = top_line as f32; self.scroll_t = 0.0; - - let current_surfaces = self.current_surfaces; - self.current_surfaces = new_surfaces; - self.old_surfaces.push_back(current_surfaces); - - if self.old_surfaces.len() > 5 { - self.old_surfaces.pop_front(); - } } } _ => {} diff --git a/src/renderer/utils.rs b/src/renderer/utils.rs deleted file mode 100644 index bfc4941..0000000 --- a/src/renderer/utils.rs +++ /dev/null @@ -1,99 +0,0 @@ -fn compute_text_region(grid_pos: (u64, u64), cell_width: u64, font_width: f32, font_height: f32) -> Rect { - let (grid_x, grid_y) = grid_pos; - let x = grid_x as f32 * font_width; - let y = grid_y as f32 * font_height; - let width = cell_width as f32 * font_width as f32; - let height = font_height as f32; - Rect::new(x, y, x + width, y + height) -} - -fn draw_background( - canvas: &mut Canvas, - grid_pos: (u64, u64), - cell_width: u64, - style: &Option>, - default_style: &Arc