diff options
author | Christian Duerr <chrisduerr@users.noreply.github.com> | 2019-04-19 12:07:56 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-19 12:07:56 +0000 |
commit | 6716c81c08c10477d2370d7e1ca56e31348a7fa3 (patch) | |
tree | bd35a36361e9c65423a30ce1c0ea37386ee3a3d7 /src | |
parent | badc41e1d02eb0ed22520eda529b254216b9a2fc (diff) | |
download | r-alacritty-6716c81c08c10477d2370d7e1ca56e31348a7fa3.tar.gz r-alacritty-6716c81c08c10477d2370d7e1ca56e31348a7fa3.tar.bz2 r-alacritty-6716c81c08c10477d2370d7e1ca56e31348a7fa3.zip |
Fix update_lines performance issues
This resolves performance issues with the `update_lines` method that
were caused by excessive updates without underlines or strikeout
present.
This also resolves a bug that was causing the underline and strikeout to
extend beyond the end of line in some rare cases.
This fixes #114.
Diffstat (limited to 'src')
-rw-r--r-- | src/display.rs | 4 | ||||
-rw-r--r-- | src/index.rs | 8 | ||||
-rw-r--r-- | src/renderer/rects.rs | 99 | ||||
-rw-r--r-- | src/term/mod.rs | 8 |
4 files changed, 64 insertions, 55 deletions
diff --git a/src/display.rs b/src/display.rs index 58c58e3a..25c4855a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -415,7 +415,7 @@ impl Display { pty_size.height -= pty_size.cell_height * message.text(&size).len() as f32; } - if previous_cols != size.cols() || previous_lines != size.lines() { + if previous_cols != size.cols() || previous_lines != size.lines() { pty_resize_handle.on_resize(&pty_size); } @@ -489,7 +489,7 @@ impl Display { // Iterate over all non-empty cells in the grid for cell in grid_cells { // Update underline/strikeout - rects.update_lines(&cell); + rects.update_lines(&size_info, &cell); // Draw the cell api.render_cell(cell, glyph_cache); diff --git a/src/index.rs b/src/index.rs index 0351c0ee..f6ea4ad3 100644 --- a/src/index.rs +++ b/src/index.rs @@ -19,6 +19,8 @@ use std::cmp::{Ord, Ordering}; use std::fmt; use std::ops::{self, Add, AddAssign, Deref, Range, RangeInclusive, Sub, SubAssign}; +use crate::term::RenderableCell; + /// The side of a cell #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Side { @@ -69,6 +71,12 @@ impl From<Point> for Point<usize> { } } +impl From<&RenderableCell> for Point<Line> { + fn from(cell: &RenderableCell) -> Self { + Point::new(cell.line, cell.column) + } +} + /// A line /// /// Newtype to avoid passing values incorrectly diff --git a/src/renderer/rects.rs b/src/renderer/rects.rs index e6a45639..2e5cd85b 100644 --- a/src/renderer/rects.rs +++ b/src/renderer/rects.rs @@ -11,12 +11,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; +use font::Metrics; +use crate::index::Point; use crate::term::cell::Flags; use crate::term::color::Rgb; use crate::term::{RenderableCell, SizeInfo}; -use font::Metrics; #[derive(Debug, Copy, Clone)] pub struct Rect<T> { @@ -32,87 +32,84 @@ impl<T> Rect<T> { } } +#[derive(Debug)] +struct Line { + flag: Flags, + range: Option<(RenderableCell, Point)>, +} + +impl Line { + fn new(flag: Flags) -> Self { + Self { flag, range: None } + } +} + /// Rects for underline, strikeout and more. pub struct Rects<'a> { inner: Vec<(Rect<f32>, Rgb)>, - last_starts: HashMap<Flags, Option<RenderableCell>>, - last_cell: Option<RenderableCell>, + active_lines: Vec<Line>, metrics: &'a Metrics, size: &'a SizeInfo, } impl<'a> Rects<'a> { pub fn new(metrics: &'a Metrics, size: &'a SizeInfo) -> Self { - let mut last_starts = HashMap::new(); - last_starts.insert(Flags::UNDERLINE, None); - last_starts.insert(Flags::STRIKEOUT, None); - - Self { inner: Vec::new(), last_cell: None, last_starts, metrics, size } + let active_lines = vec![Line::new(Flags::UNDERLINE), Line::new(Flags::STRIKEOUT)]; + Self { inner: Vec::new(), active_lines, metrics, size } } /// Convert the stored rects to rectangles for the renderer. - pub fn rects(mut self) -> Vec<(Rect<f32>, Rgb)> { - // If there's still a line pending, draw it until the last cell - for (flag, start_cell) in self.last_starts.iter_mut() { - if let Some(start) = start_cell { - self.inner.push(create_rect( - &start, - &self.last_cell.unwrap(), - *flag, - &self.metrics, - &self.size, - )); - } - } - - self.inner + pub fn rects(&self) -> &Vec<(Rect<f32>, Rgb)> { + &self.inner } /// Update the stored lines with the next cell info. - pub fn update_lines(&mut self, cell: &RenderableCell) { - for (flag, start_cell) in self.last_starts.iter_mut() { - let flag = *flag; - *start_cell = match *start_cell { + pub fn update_lines(&mut self, size_info: &SizeInfo, cell: &RenderableCell) { + for line in self.active_lines.iter_mut() { + match line.range { // Check for end if line is present - Some(ref mut start) => { - let last_cell = self.last_cell.unwrap(); - + Some((ref mut start, ref mut end)) => { // No change in line if cell.line == start.line - && cell.flags.contains(flag) + && cell.flags.contains(line.flag) && cell.fg == start.fg - && cell.column == last_cell.column + 1 + && cell.column == end.col + 1 { + if size_info.cols() == cell.column && size_info.lines() == cell.line { + // Add the last rect if we've reached the end of the terminal + self.inner.push(create_rect( + &start, + cell.into(), + line.flag, + &self.metrics, + &self.size, + )); + } else { + // Update the length of the line + *end = cell.into(); + } + continue; } - self.inner.push(create_rect( - &start, - &last_cell, - flag, - &self.metrics, - &self.size, - )); + self.inner.push(create_rect(start, *end, line.flag, &self.metrics, &self.size)); // Start a new line if the flag is present - if cell.flags.contains(flag) { - Some(*cell) + if cell.flags.contains(line.flag) { + *start = *cell; + *end = cell.into(); } else { - None + line.range = None; } }, // Check for new start of line None => { - if cell.flags.contains(flag) { - Some(*cell) - } else { - None + if cell.flags.contains(line.flag) { + line.range = Some((*cell, cell.into())); } }, }; } - - self.last_cell = Some(*cell); } // Add a rectangle @@ -125,13 +122,13 @@ impl<'a> Rects<'a> { /// of `end`, based on the given flag and size metrics. fn create_rect( start: &RenderableCell, - end: &RenderableCell, + end: Point, flag: Flags, metrics: &Metrics, size: &SizeInfo, ) -> (Rect<f32>, Rgb) { let start_x = start.column.0 as f32 * size.cell_width; - let end_x = (end.column.0 + 1) as f32 * size.cell_width; + let end_x = (end.col.0 + 1) as f32 * size.cell_width; let width = end_x - start_x; let (position, mut height) = match flag { diff --git a/src/term/mod.rs b/src/term/mod.rs index 3178de4c..48eedef1 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -1318,7 +1318,9 @@ impl Term { lines = min(lines, self.scroll_region.end - origin); // Scroll between origin and bottom - self.grid.scroll_down(&(origin..self.scroll_region.end), lines, &self.cursor.template); + let mut template = self.cursor.template; + template.flags = Flags::empty(); + self.grid.scroll_down(&(origin..self.scroll_region.end), lines, &template); } /// Scroll screen up @@ -1331,7 +1333,9 @@ impl Term { let lines = min(lines, self.scroll_region.end - self.scroll_region.start); // Scroll from origin to bottom less number of lines - self.grid.scroll_up(&(origin..self.scroll_region.end), lines, &self.cursor.template); + let mut template = self.cursor.template; + template.flags = Flags::empty(); + self.grid.scroll_up(&(origin..self.scroll_region.end), lines, &template); } fn deccolm(&mut self) { |