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_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(

@ -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,

@ -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(

@ -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<SurfacePair>,
snapshots: VecDeque<SnapshotPair>,
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();
}
}
}
_ => {}

@ -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")]
fn windows_fix_dpi() {
println!("dpi fix applied");
use winapi::shared::windef::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
use winapi::um::winuser::SetProcessDpiAwarenessContext;
unsafe {

@ -362,11 +362,12 @@ impl Sdl2WindowWrapper {
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
log::debug!("Render Triggered");
let scaling = sdl_window_wrapper.scale_factor();
let renderer = &mut self.renderer;
self.skulpin_renderer.draw(
&sdl_window_wrapper,
|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);
}
},

Loading…
Cancel
Save