From 3cc0d5c1734b30f0c24674b8902e63c0b74bf0be Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Thu, 23 Sep 2021 12:54:23 -0700 Subject: [PATCH] rework draw commands to send whole line at once and draw background before foreground --- src/editor/window.rs | 73 +++++++++++++++------------- src/renderer/cursor_renderer/mod.rs | 2 +- src/renderer/fonts/caching_shaper.rs | 11 ++--- src/renderer/grid_renderer.rs | 4 +- src/renderer/rendered_window.rs | 36 +++++++++----- 5 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/editor/window.rs b/src/editor/window.rs index 04dcdc3..44f967d 100644 --- a/src/editor/window.rs +++ b/src/editor/window.rs @@ -9,20 +9,23 @@ use super::style::Style; use super::{AnchorInfo, DrawCommand, DrawCommandBatcher}; use crate::bridge::GridLineCell; -#[derive(new, Clone, Debug)] +#[derive(Clone, Debug)] +pub struct LineFragment { + pub text: String, + pub window_left: u64, + pub window_top: u64, + pub width: u64, + pub style: Option>, +} + +#[derive(Clone, Debug)] pub enum WindowDrawCommand { Position { grid_position: (f64, f64), grid_size: (u64, u64), floating_order: Option, }, - Cells { - cells: Vec, - window_left: u64, - window_top: u64, - width: u64, - style: Option>, - }, + DrawLine(Vec), Scroll { top: u64, bottom: u64, @@ -179,14 +182,14 @@ impl Window { *previous_style = style; } - // Send a draw command for the given row starting from current_start up until the next style + // Build a line fragment for the given row starting from current_start up until the next style // change or double width character. - fn send_draw_command(&self, row_index: u64, start: u64) -> Option { + fn build_line_fragment(&self, row_index: u64, start: u64) -> (u64, LineFragment) { let row = self.grid.row(row_index).unwrap(); let (_, style) = &row[start as usize]; - let mut cells = Vec::new(); + let mut text = String::new(); let mut width = 0; for possible_end_index in start..self.grid.width { let (character, possible_end_style) = &row[possible_end_index as usize]; @@ -203,19 +206,35 @@ impl Window { } // Add the grid cell to the cells to render - cells.push(character.clone()); + text.push_str(character); } - // Send a window draw command to the current window. - self.send_command(WindowDrawCommand::Cells { - cells, + let line_fragment = LineFragment { + text, window_left: start, window_top: row_index, width, style: style.clone(), - }); + }; - Some(start + width) + (start + width, line_fragment) + } + + + // Redraw line by calling build_line_fragment starting at 0 + // until current_start is greater than the grid width and sending the resulting + // fragments as a batch + fn redraw_line(&self, row: u64) { + // until current_start is greater than the grid width and sending the resulting + // fragments as a batch + let mut current_start = 0; + let mut line_fragments = Vec::new(); + while current_start < self.grid.width { + let (next_start, line_fragment) = self.build_line_fragment(row, current_start); + current_start = next_start; + line_fragments.push(line_fragment); + } + self.send_command(WindowDrawCommand::DrawLine(line_fragments)); } pub fn draw_grid_line( @@ -238,16 +257,7 @@ impl Window { ); } - // Redraw the participating line by calling send_draw_command starting at 0 - // until current_start is greater than the grid width - let mut current_start = 0; - while current_start < self.grid.width { - if let Some(next_start) = self.send_draw_command(row, current_start) { - current_start = next_start; - } else { - break; - } - } + self.redraw_line(row); } else { warn!("Draw command out of bounds"); } @@ -312,14 +322,7 @@ impl Window { pub fn redraw(&self) { self.send_command(WindowDrawCommand::Clear); for row in 0..self.grid.height { - let mut current_start = 0; - while current_start < self.grid.width { - if let Some(next_start) = self.send_draw_command(row, current_start) { - current_start = next_start; - } else { - break; - } - } + self.redraw_line(row); } } diff --git a/src/renderer/cursor_renderer/mod.rs b/src/renderer/cursor_renderer/mod.rs index 2e7a559..b0f4f89 100644 --- a/src/renderer/cursor_renderer/mod.rs +++ b/src/renderer/cursor_renderer/mod.rs @@ -373,7 +373,7 @@ impl CursorRenderer { let y_adjustment = grid_renderer.shaper.y_adjustment(); let blobs = &grid_renderer .shaper - .shape_cached(&[character], false, false); + .shape_cached(character, false, false); for blob in blobs.iter() { canvas.draw_text_blob( diff --git a/src/renderer/fonts/caching_shaper.rs b/src/renderer/fonts/caching_shaper.rs index 0da30eb..70ce069 100644 --- a/src/renderer/fonts/caching_shaper.rs +++ b/src/renderer/fonts/caching_shaper.rs @@ -14,7 +14,7 @@ use super::font_options::*; #[derive(new, Clone, Hash, PartialEq, Eq, Debug)] struct ShapeKey { - pub cells: Vec, + pub text: String, pub bold: bool, pub italic: bool, } @@ -229,13 +229,12 @@ impl CachingShaper { grouped_results } - pub fn shape(&mut self, cells: &[String], bold: bool, italic: bool) -> Vec { + pub fn shape(&mut self, text: String, bold: bool, italic: bool) -> Vec { let current_size = self.current_size(); let (glyph_width, ..) = self.font_base_dimensions(); let mut resulting_blobs = Vec::new(); - let text = cells.concat(); trace!("Shaping text: {}", text); for (cluster_group, font_pair) in self.build_clusters(&text, bold, italic) { @@ -279,11 +278,11 @@ impl CachingShaper { resulting_blobs } - pub fn shape_cached(&mut self, cells: &[String], bold: bool, italic: bool) -> &Vec { - let key = ShapeKey::new(cells.to_vec(), bold, italic); + pub fn shape_cached(&mut self, text: String, bold: bool, italic: bool) -> &Vec { + let key = ShapeKey::new(text.clone(), bold, italic); if !self.blob_cache.contains(&key) { - let blobs = self.shape(cells, bold, italic); + let blobs = self.shape(text, bold, italic); self.blob_cache.put(key.clone(), blobs); } diff --git a/src/renderer/grid_renderer.rs b/src/renderer/grid_renderer.rs index 54fe42f..3d0d589 100644 --- a/src/renderer/grid_renderer.rs +++ b/src/renderer/grid_renderer.rs @@ -103,7 +103,7 @@ impl GridRenderer { pub fn draw_foreground( &mut self, canvas: &mut Canvas, - cells: &[String], + text: String, grid_position: (u64, u64), cell_width: u64, style: &Option>, @@ -163,7 +163,7 @@ impl GridRenderer { for blob in self .shaper - .shape_cached(cells, style.bold, style.italic) + .shape_cached(text, style.bold, style.italic) .iter() { canvas.draw_text_blob(blob, (x as f32, (y + y_adjustment) as f32), &self.paint); diff --git a/src/renderer/rendered_window.rs b/src/renderer/rendered_window.rs index 63d070d..29bc342 100644 --- a/src/renderer/rendered_window.rs +++ b/src/renderer/rendered_window.rs @@ -9,7 +9,7 @@ use skia_safe::{ use super::animation_utils::*; use super::{GridRenderer, RendererSettings}; -use crate::editor::WindowDrawCommand; +use crate::editor::{WindowDrawCommand, LineFragment}; use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::utils::Dimensions; @@ -335,19 +335,33 @@ impl RenderedWindow { self.grid_destination = new_destination; } } - WindowDrawCommand::Cells { - cells, - window_left, - window_top, - width, - style, - } => { - let grid_position = (window_left, window_top); + WindowDrawCommand::DrawLine(line_fragments) => { let canvas = self.current_surface.surface.canvas(); canvas.save(); - grid_renderer.draw_background(canvas, grid_position, width, &style); - grid_renderer.draw_foreground(canvas, &cells, grid_position, width, &style); + for line_fragment in line_fragments.iter() { + let LineFragment { + window_left, + window_top, + width, + style, + .. + } = line_fragment; + let grid_position = (*window_left, *window_top); + grid_renderer.draw_background(canvas, grid_position, *width, &style); + } + + for line_fragment in line_fragments.into_iter() { + let LineFragment { + text, + window_left, + window_top, + width, + style + } = line_fragment; + let grid_position = (window_left, window_top); + grid_renderer.draw_foreground(canvas, text, grid_position, width, &style); + } canvas.restore(); } WindowDrawCommand::Scroll {