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 <grinsladeg@gmail.com>
macos-click-through
Keith Simmons 4 years ago committed by GitHub
parent cd212ca884
commit 33f6a4b914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -166,11 +166,13 @@ impl Window {
self.grid_left = grid_left; self.grid_left = grid_left;
self.grid_top = grid_top; self.grid_top = grid_top;
self.send_updated_position(); self.send_updated_position();
self.redraw();
} }
pub fn resize(&mut self, width: u64, height: u64) { pub fn resize(&mut self, width: u64, height: u64) {
self.grid.resize(width, height); self.grid.resize(width, height);
self.send_updated_position(); self.send_updated_position();
self.redraw();
} }
fn modify_grid( fn modify_grid(

@ -247,13 +247,18 @@ impl CursorRenderer {
let (cursor_grid_x, cursor_grid_y) = self.cursor.grid_position; let (cursor_grid_x, cursor_grid_y) = self.cursor.grid_position;
if let Some(window) = windows.get(&self.cursor.parent_window_id) { if let Some(window) = windows.get(&self.cursor.parent_window_id) {
self.destination = ( let grid_x = cursor_grid_x as f32 + window.grid_current_position.x;
(cursor_grid_x as f32 + window.grid_current_position.x) * font_width, let mut grid_y = cursor_grid_y as f32 + window.grid_current_position.y
(cursor_grid_y as f32 + window.grid_current_position.y - (window.current_scroll - window.current_surfaces.top_line);
- (window.current_scroll - window.current_surfaces.top_line))
* font_height, // 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
.into(); // 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 { } else {
self.destination = ( self.destination = (
cursor_grid_x as f32 * font_width, cursor_grid_x as f32 * font_width,

@ -217,7 +217,12 @@ impl Renderer {
canvas.restore(); 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); warn!("{:?}", &draw_command);
match draw_command { match draw_command {
DrawCommand::Window { DrawCommand::Window {
@ -228,7 +233,8 @@ impl Renderer {
} }
DrawCommand::Window { grid_id, command } => { DrawCommand::Window { grid_id, command } => {
if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) { 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); self.rendered_windows.insert(grid_id, rendered_window);
} else if let WindowDrawCommand::Position { } else if let WindowDrawCommand::Position {
grid_left, grid_left,
@ -246,6 +252,7 @@ impl Renderer {
(grid_left as f32, grid_top as f32).into(), (grid_left as f32, grid_top as f32).into(),
width, width,
height, height,
scaling,
); );
self.rendered_windows.insert(grid_id, new_window); self.rendered_windows.insert(grid_id, new_window);
} else { } else {
@ -273,6 +280,7 @@ impl Renderer {
root_canvas: &mut Canvas, root_canvas: &mut Canvas,
coordinate_system_helper: &CoordinateSystemHelper, coordinate_system_helper: &CoordinateSystemHelper,
dt: f32, dt: f32,
scaling: f32,
) -> bool { ) -> bool {
trace!("Rendering"); trace!("Rendering");
let mut font_changed = false; let mut font_changed = false;
@ -287,7 +295,7 @@ impl Renderer {
if let DrawCommand::FontChanged(_) = draw_command { if let DrawCommand::FontChanged(_) = draw_command {
font_changed = true; font_changed = true;
} }
self.handle_draw_command(root_canvas, draw_command); self.handle_draw_command(root_canvas, draw_command, scaling);
} }
root_canvas.clear( root_canvas.clear(

@ -1,10 +1,10 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::iter;
use skulpin::skia_safe::canvas::{SaveLayerRec, SrcRectConstraint}; use skulpin::skia_safe::canvas::{SaveLayerRec, SrcRectConstraint};
use skulpin::skia_safe::gpu::SurfaceOrigin; use skulpin::skia_safe::gpu::SurfaceOrigin;
use skulpin::skia_safe::{ 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::*; use super::animation_utils::*;
@ -45,9 +45,10 @@ fn build_window_surface_with_grid_size(
renderer: &Renderer, renderer: &Renderer,
grid_width: u64, grid_width: u64,
grid_height: u64, grid_height: u64,
scaling: f32,
) -> Surface { ) -> Surface {
let pixel_width = (grid_width as f32 * renderer.font_width) 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) as i32; let pixel_height = (grid_height as f32 * renderer.font_height / scaling) as i32;
build_window_surface(parent_canvas, pixel_width, pixel_height) build_window_surface(parent_canvas, pixel_width, pixel_height)
} }
@ -56,28 +57,30 @@ fn build_background_window_surface(
renderer: &Renderer, renderer: &Renderer,
grid_width: u64, grid_width: u64,
grid_height: u64, grid_height: u64,
scaling: f32,
) -> Surface { ) -> Surface {
let mut surface = let mut surface = build_window_surface_with_grid_size(
build_window_surface_with_grid_size(parent_canvas, renderer, grid_width, grid_height); parent_canvas,
renderer,
grid_width,
grid_height,
scaling,
);
let canvas = surface.canvas(); let canvas = surface.canvas();
canvas.clear(renderer.get_default_background()); canvas.clear(renderer.get_default_background());
surface surface
} }
fn clone_window_surface(surface: &mut Surface) -> Surface { pub struct SnapshotPair {
let snapshot = surface.image_snapshot(); background: Image,
let mut canvas = surface.canvas(); foreground: Image,
let mut new_surface = build_window_surface(&mut canvas, snapshot.width(), snapshot.height()); top_line: f32,
let new_canvas = new_surface.canvas();
new_canvas.draw_image(snapshot, (0.0, 0.0), None);
new_surface
} }
pub struct SurfacePair { pub struct SurfacePair {
background: Surface, background: Surface,
foreground: Surface, foreground: Surface,
pub top_line: f32, pub top_line: f32,
bottom_line: f32,
} }
impl SurfacePair { impl SurfacePair {
@ -87,43 +90,51 @@ impl SurfacePair {
grid_width: u64, grid_width: u64,
grid_height: u64, grid_height: u64,
top_line: f32, top_line: f32,
bottom_line: f32, scaling: f32,
) -> SurfacePair { ) -> SurfacePair {
let background = let background = build_background_window_surface(
build_background_window_surface(parent_canvas, renderer, grid_width, grid_height); parent_canvas,
let foreground = renderer,
build_window_surface_with_grid_size(parent_canvas, renderer, grid_width, grid_height); grid_width,
grid_height,
scaling,
);
let foreground = build_window_surface_with_grid_size(
parent_canvas,
renderer,
grid_width,
grid_height,
scaling,
);
SurfacePair { SurfacePair {
background, background,
foreground, foreground,
top_line, top_line,
bottom_line,
} }
} }
fn clone(&mut self) -> SurfacePair { fn snapshot(&mut self) -> SnapshotPair {
let new_background = clone_window_surface(&mut self.background); let background = self.background.image_snapshot();
let new_foreground = clone_window_surface(&mut self.foreground); let foreground = self.foreground.image_snapshot();
SurfacePair { SnapshotPair {
background: new_background, background,
foreground: new_foreground, foreground,
top_line: self.top_line, top_line: self.top_line,
bottom_line: self.bottom_line,
} }
} }
} }
pub struct RenderedWindow { pub struct RenderedWindow {
old_surfaces: VecDeque<SurfacePair>, snapshots: VecDeque<SnapshotPair>,
pub current_surfaces: SurfacePair, pub current_surfaces: SurfacePair,
pub id: u64, pub id: u64,
pub hidden: bool, pub hidden: bool,
pub floating: bool, pub floating: bool,
grid_width: u64, pub grid_width: u64,
grid_height: u64, pub grid_height: u64,
grid_start_position: Point, grid_start_position: Point,
pub grid_current_position: Point, pub grid_current_position: Point,
@ -150,12 +161,19 @@ impl RenderedWindow {
grid_position: Point, grid_position: Point,
grid_width: u64, grid_width: u64,
grid_height: u64, grid_height: u64,
scaling: f32,
) -> RenderedWindow { ) -> RenderedWindow {
let current_surfaces = let current_surfaces = SurfacePair::new(
SurfacePair::new(parent_canvas, renderer, grid_width, grid_height, 0.0, 0.0); parent_canvas,
renderer,
grid_width,
grid_height,
0.0,
scaling,
);
RenderedWindow { RenderedWindow {
old_surfaces: VecDeque::new(), snapshots: VecDeque::new(),
current_surfaces, current_surfaces,
id, id,
hidden: false, hidden: false,
@ -213,7 +231,7 @@ impl RenderedWindow {
if (self.scroll_t - 1.0).abs() < std::f32::EPSILON { 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 // We are at destination, move t out of 0-1 range to stop the animation
self.scroll_t = 2.0; self.scroll_t = 2.0;
self.old_surfaces.clear(); self.snapshots.clear();
} else { } else {
animating = true; animating = true;
self.scroll_t = (self.scroll_t + dt / settings.scroll_animation_length).min(1.0); 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)); paint.set_color(Color::from_argb(a, 255, 255, 255));
for surface_pair in iter::once(&mut self.current_surfaces) // Draw background scrolling snapshots
.chain(self.old_surfaces.iter_mut()) for snapshot_pair in self.snapshots.iter_mut().rev() {
.rev()
{
let scroll_offset = let scroll_offset =
surface_pair.top_line * font_height - self.current_scroll * font_height; snapshot_pair.top_line * font_height - self.current_scroll * font_height;
surface_pair.background.draw( let background_snapshot = &mut snapshot_pair.background;
root_canvas.as_mut(), root_canvas.draw_image_rect(
(pixel_region.left(), pixel_region.top() + scroll_offset), background_snapshot,
Some(&paint), 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(); root_canvas.restore();
} }
{ {
// Save layer so that text may safely overwrite images underneath // Save layer so that text may safely overwrite images underneath
root_canvas.save_layer(&SaveLayerRec::default()); root_canvas.save_layer(&SaveLayerRec::default());
for surface_pair in iter::once(&mut self.current_surfaces)
.chain(self.old_surfaces.iter_mut()) // Draw foreground scrolling snapshots
.rev() for snapshot_pair in self.snapshots.iter_mut().rev() {
{
let scroll_offset = let scroll_offset =
surface_pair.top_line * font_height - self.current_scroll * font_height; snapshot_pair.top_line * font_height - self.current_scroll * font_height;
surface_pair.foreground.draw( let foreground_snapshot = &mut snapshot_pair.foreground;
root_canvas.as_mut(), root_canvas.draw_image_rect(
(pixel_region.left(), pixel_region.top() + scroll_offset), foreground_snapshot,
Some(&paint), 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(); root_canvas.restore();
} }
@ -325,6 +366,7 @@ impl RenderedWindow {
mut self, mut self,
renderer: &mut Renderer, renderer: &mut Renderer,
draw_command: WindowDrawCommand, draw_command: WindowDrawCommand,
scaling: f32,
) -> Self { ) -> Self {
match draw_command { match draw_command {
WindowDrawCommand::Position { WindowDrawCommand::Position {
@ -360,6 +402,7 @@ impl RenderedWindow {
&renderer, &renderer,
grid_width, grid_width,
grid_height, grid_height,
scaling,
); );
old_background.draw( old_background.draw(
self.current_surfaces.background.canvas(), self.current_surfaces.background.canvas(),
@ -375,6 +418,7 @@ impl RenderedWindow {
&renderer, &renderer,
grid_width, grid_width,
grid_height, grid_height,
scaling,
); );
old_foreground.draw( old_foreground.draw(
self.current_surfaces.foreground.canvas(), self.current_surfaces.foreground.canvas(),
@ -406,24 +450,19 @@ impl RenderedWindow {
let grid_position = (window_left, window_top); let grid_position = (window_left, window_top);
{ {
let mut background_canvas = self.current_surfaces.background.canvas(); let canvas = self.current_surfaces.background.canvas();
renderer.draw_background( canvas.save();
&mut background_canvas, canvas.scale((1.0 / scaling, 1.0 / scaling));
grid_position, renderer.draw_background(canvas, grid_position, cell_width, &style);
cell_width, canvas.restore();
&style,
);
} }
{ {
let mut foreground_canvas = self.current_surfaces.foreground.canvas(); let canvas = self.current_surfaces.foreground.canvas();
renderer.draw_foreground( canvas.save();
&mut foreground_canvas, canvas.scale((1.0 / scaling, 1.0 / scaling));
&text, renderer.draw_foreground(canvas, &text, grid_position, cell_width, &style);
grid_position, canvas.restore();
cell_width,
&style,
);
} }
} }
WindowDrawCommand::Scroll { WindowDrawCommand::Scroll {
@ -435,12 +474,18 @@ impl RenderedWindow {
cols, cols,
} => { } => {
let scrolled_region = Rect::new( let scrolled_region = Rect::new(
left as f32 * renderer.font_width, left as f32 * renderer.font_width / scaling,
top as f32 * renderer.font_height, top as f32 * renderer.font_height / scaling,
right as f32 * renderer.font_width, right as f32 * renderer.font_width / scaling,
bot as f32 * renderer.font_height, 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_snapshot = self.current_surfaces.background.image_snapshot();
let background_canvas = self.current_surfaces.background.canvas(); let background_canvas = self.current_surfaces.background.canvas();
@ -448,12 +493,6 @@ impl RenderedWindow {
background_canvas.save(); background_canvas.save();
background_canvas.clip_rect(scrolled_region, None, Some(false)); 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_canvas.draw_image_rect(
background_snapshot, background_snapshot,
Some((&scrolled_region, SrcRectConstraint::Fast)), Some((&scrolled_region, SrcRectConstraint::Fast)),
@ -471,12 +510,6 @@ impl RenderedWindow {
foreground_canvas.save(); foreground_canvas.save();
foreground_canvas.clip_rect(scrolled_region, None, Some(false)); 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_canvas.draw_image_rect(
foreground_snapshot, foreground_snapshot,
Some((&scrolled_region, SrcRectConstraint::Fast)), Some((&scrolled_region, SrcRectConstraint::Fast)),
@ -488,21 +521,23 @@ impl RenderedWindow {
} }
} }
WindowDrawCommand::Clear => { WindowDrawCommand::Clear => {
let background_canvas = self.current_surfaces.background.canvas();
self.current_surfaces.background = build_background_window_surface( self.current_surfaces.background = build_background_window_surface(
background_canvas, self.current_surfaces.background.canvas(),
&renderer, &renderer,
self.grid_width, self.grid_width,
self.grid_height, self.grid_height,
scaling,
); );
let foreground_canvas = self.current_surfaces.foreground.canvas();
self.current_surfaces.foreground = build_window_surface_with_grid_size( self.current_surfaces.foreground = build_window_surface_with_grid_size(
foreground_canvas, self.current_surfaces.foreground.canvas(),
&renderer, &renderer,
self.grid_width, self.grid_width,
self.grid_height, self.grid_height,
scaling,
); );
self.snapshots.clear();
} }
WindowDrawCommand::Show => { WindowDrawCommand::Show => {
if self.hidden { if self.hidden {
@ -512,27 +547,21 @@ impl RenderedWindow {
} }
} }
WindowDrawCommand::Hide => self.hidden = true, WindowDrawCommand::Hide => self.hidden = true,
WindowDrawCommand::Viewport { WindowDrawCommand::Viewport { top_line, .. } => {
top_line,
bottom_line,
} => {
if (self.current_surfaces.top_line - top_line as f32).abs() > std::f32::EPSILON { if (self.current_surfaces.top_line - top_line as f32).abs() > std::f32::EPSILON {
let mut new_surfaces = self.current_surfaces.clone(); let new_snapshot = self.current_surfaces.snapshot();
new_surfaces.top_line = top_line as f32; self.snapshots.push_back(new_snapshot);
new_surfaces.bottom_line = bottom_line as f32;
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 // Set new target viewport position and initialize animation timer
self.start_scroll = self.current_scroll; self.start_scroll = self.current_scroll;
self.scroll_destination = top_line as f32; self.scroll_destination = top_line as f32;
self.scroll_t = 0.0; 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();
}
} }
} }
_ => {} _ => {}

@ -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<Arc<Style>>,
default_style: &Arc<Style>,
floating: bool,
settings: &RendererSettings
) {
self.paint.set_blend_mode(BlendMode::Src);
let region = self.compute_text_region(grid_pos, cell_width);
let style = style.as_ref().unwrap_or(default_style);
let mut color = style.background(&default_style.colors);
if floating {
color.a = color.a * settings.floating_opacity.min(1.0).max(0.0);
}
self.paint.set_color(color.to_color());
canvas.draw_rect(region, &self.paint);
}
fn draw_foreground(
canvas: &mut Canvas,
text: &str,
grid_pos: (u64, u64),
cell_width: u64,
style: &Option<Arc<Style>>,
default_style: &Arc<Style>,
) {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = cell_width as f32 * self.font_width;
let style = style.as_ref().unwrap_or(default_style);
canvas.save();
let region = self.compute_text_region(grid_pos, cell_width);
canvas.clip_rect(region, None, Some(false));
if style.underline || style.undercurl {
let line_position = self.shaper.underline_position();
let stroke_width = self.shaper.options.size / 10.0;
self.paint
.set_color(style.special(&default_style.colors).to_color());
self.paint.set_stroke_width(stroke_width);
if style.undercurl {
self.paint.set_path_effect(dash_path_effect::new(
&[stroke_width * 2.0, stroke_width * 2.0],
0.0,
));
} else {
self.paint.set_path_effect(None);
}
canvas.draw_line(
(x, y - line_position + self.font_height),
(x + width, y - line_position + self.font_height),
&self.paint,
);
}
self.paint
.set_color(style.foreground(&default_style.colors).to_color());
let text = text.trim_end();
if !text.is_empty() {
for blob in self
.shaper
.shape_cached(text, style.bold, style.italic)
.iter()
{
canvas.draw_text_blob(blob, (x, y), &self.paint);
}
}
if style.strikethrough {
let line_position = region.center_y();
self.paint
.set_color(style.special(&default_style.colors).to_color());
canvas.draw_line((x, line_position), (x + width, line_position), &self.paint);
}
canvas.restore();
}

@ -66,6 +66,7 @@ pub fn window_geometry_or_default() -> (u64, u64) {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn windows_fix_dpi() { fn windows_fix_dpi() {
println!("dpi fix applied");
use winapi::shared::windef::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; use winapi::shared::windef::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
use winapi::um::winuser::SetProcessDpiAwarenessContext; use winapi::um::winuser::SetProcessDpiAwarenessContext;
unsafe { unsafe {

@ -362,11 +362,12 @@ impl Sdl2WindowWrapper {
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle { if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
log::debug!("Render Triggered"); log::debug!("Render Triggered");
let scaling = sdl_window_wrapper.scale_factor();
let renderer = &mut self.renderer; let renderer = &mut self.renderer;
self.skulpin_renderer.draw( self.skulpin_renderer.draw(
&sdl_window_wrapper, &sdl_window_wrapper,
|canvas, coordinate_system_helper| { |canvas, coordinate_system_helper| {
if renderer.draw_frame(canvas, &coordinate_system_helper, dt) { if renderer.draw_frame(canvas, &coordinate_system_helper, dt, scaling as f32) {
handle_new_grid_size(current_size, &renderer, &ui_command_sender); handle_new_grid_size(current_size, &renderer, &ui_command_sender);
} }
}, },

Loading…
Cancel
Save