From e676af8f91e8b25513f84f7cd9e814a81906d9ae Mon Sep 17 00:00:00 2001 From: daa84 Date: Tue, 21 Mar 2017 13:10:55 +0300 Subject: [PATCH] Finish area readrawing optimization --- src/shell.rs | 12 +++--- src/ui_model.rs | 103 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/shell.rs b/src/shell.rs index cb7e827..24ee56f 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -277,8 +277,9 @@ fn draw(shell: &Shell, ctx: &cairo::Context) { let line_height = shell.line_height.unwrap(); let char_width = shell.char_width.unwrap(); let clip = ctx.clip_extents(); - let model_clip = ModelRect::from_area(line_height, char_width, + let mut model_clip = ModelRect::from_area(line_height, char_width, clip.0, clip.1, clip.2, clip.3); + shell.model.limit_to_model(&mut model_clip); let line_x = model_clip.left as f64 * char_width; let mut line_y: f64 = model_clip.top as f64 * line_height; @@ -291,16 +292,15 @@ fn draw(shell: &Shell, ctx: &cairo::Context) { let layout = pc::create_layout(ctx); let mut desc = shell.create_pango_font(); - // FIXME: col_idx is wrong for (line_idx, line) in shell.model.clip_model(&model_clip) { ctx.move_to(line_x, line_y); // first draw background // here we join same bg color for given line // this gives less drawing primitives - let mut from_col_idx = 0; + let mut from_col_idx = model_clip.left; let mut from_bg = None; - for (col_idx, cell) in line.iter().enumerate() { + for (col_idx, cell) in line.iter() { let (bg, _) = shell.colors(cell); if from_bg.is_none() { @@ -321,14 +321,14 @@ fn draw(shell: &Shell, ctx: &cairo::Context) { draw_joined_rect(shell, ctx, from_col_idx, - line.len(), + model_clip.right + 1, char_width, line_height, from_bg.take().unwrap()); ctx.move_to(line_x, line_y); - for (col_idx, cell) in line.iter().enumerate() { + for (col_idx, cell) in line.iter() { let double_width = line.get(col_idx + 1).map(|c| c.attrs.double_width).unwrap_or(false); let current_point = ctx.get_current_point(); diff --git a/src/ui_model.rs b/src/ui_model.rs index 5b1e330..4515fcb 100644 --- a/src/ui_model.rs +++ b/src/ui_model.rs @@ -121,6 +121,29 @@ impl UiModel { &self.model } + pub fn limit_to_model(&self, clip: &mut ModelRect) { + clip.left = if clip.left >= self.columns { + self.columns - 1 + } else { + clip.left + }; + clip.right = if clip.right >= self.columns { + self.columns - 1 + } else { + clip.right + }; + clip.top = if clip.top >= self.rows { + self.rows - 1 + } else { + clip.top + }; + clip.bot = if clip.bot >= self.rows { + self.rows - 1 + } else { + clip.bot + }; + } + pub fn clip_model<'a> (&'a self, clip: &'a ModelRect) -> ClipRowIterator<'a> { ClipRowIterator::new(self, clip) } @@ -275,8 +298,8 @@ impl ModelRect { pub fn to_area(&self, line_height: f64, char_width: f64) -> (i32, i32, i32, i32) { (self.left as i32 * char_width as i32, self.top as i32 * line_height as i32, - (self.right - self.left + 1) as i32 * char_width as i32, - (self.bot - self.top + 1) as i32 * line_height as i32) + (self.right - self.left + 1) as i32 * char_width as i32- 1, + (self.bot - self.top + 1) as i32 * line_height as i32 - 1) } pub fn from_area(line_height: f64, char_width: f64, x1: f64, y1: f64, x2: f64, y2: f64) -> ModelRect { @@ -306,20 +329,40 @@ impl <'a> ClipRowIterator<'a> { } impl <'a> Iterator for ClipRowIterator<'a> { - type Item = (usize, ClipColIterator<'a>); + type Item = (usize, ClipLine<'a>); - fn next(&mut self) -> Option<(usize, ClipColIterator<'a>)> { + fn next(&mut self) -> Option<(usize, ClipLine<'a>)> { self.pos += 1; self.iter.next().map(|line| { - (self.rect.top + self.pos, ClipColIterator::new(line, self.rect)) + (self.rect.top + self.pos - 1, ClipLine::new(line, self.rect)) }) } } +pub struct ClipLine <'a> { + rect: &'a ModelRect, + line: &'a Vec, +} + +impl <'a> ClipLine<'a> { + pub fn new(model: &'a Vec, rect: &'a ModelRect) -> ClipLine<'a> { + ClipLine { + line: model, + rect: rect, + } + } + + pub fn get(&self, idx: usize) -> Option<&Cell> { + self.line.get(idx) + } + + pub fn iter(&self) -> ClipColIterator<'a> { + ClipColIterator::new(self.line, self.rect) + } +} + pub struct ClipColIterator<'a> { rect: &'a ModelRect, - len: usize, - line: &'a Vec, pos: usize, iter: Iter<'a, Cell>, } @@ -327,21 +370,12 @@ pub struct ClipColIterator<'a> { impl <'a> ClipColIterator<'a> { pub fn new(model: &'a Vec, rect: &'a ModelRect) -> ClipColIterator<'a> { ClipColIterator { - len: rect.right - rect.left + 1, - line: model, rect: rect, pos: 0, iter: model[rect.left..rect.right + 1].iter(), } } - pub fn len(&self) -> usize { - self.len - } - - pub fn get(&self, idx: usize) -> Option<&Cell> { - self.line.get(idx) - } } impl <'a>Iterator for ClipColIterator<'a> { @@ -350,7 +384,7 @@ impl <'a>Iterator for ClipColIterator<'a> { fn next(&mut self) -> Option<(usize, &'a Cell)> { self.pos += 1; self.iter.next().map(|line| { - (self.rect.left + self.pos, line) + (self.rect.left + self.pos - 1, line) }) } } @@ -359,13 +393,32 @@ impl <'a>Iterator for ClipColIterator<'a> { mod tests { use super::*; + #[test] + fn test_iterator_border() { + let model = UiModel::new(10, 20); + let rect = ModelRect::new(0, 9, 0, 19); + + assert_eq!(10, model.clip_model(&rect).count()); + let (_, first_line) = model.clip_model(&rect).nth(0).unwrap(); + assert_eq!(20, first_line.iter().count()); + + let (idx, _) = first_line.iter().nth(19).unwrap(); + assert_eq!(19, idx); + } + #[test] fn test_iterator() { let model = UiModel::new(10, 20); let rect = ModelRect::new(1, 2, 1, 2); assert_eq!(2, model.clip_model(&rect).count()); - assert_eq!(2, model.clip_model(&rect).nth(0).unwrap().count()); + let (idx, first_line) = model.clip_model(&rect).nth(0).unwrap(); + + assert_eq!(1, idx); + assert_eq!(2, first_line.iter().count()); + + let (idx, _) = first_line.iter().nth(0).unwrap(); + assert_eq!(1, idx); } #[test] @@ -376,6 +429,14 @@ mod tests { assert_eq!(0, rect.left); assert_eq!(1, rect.bot); assert_eq!(1, rect.right); + + + let rect = ModelRect::from_area(10.0, 5.0, 0.0, 0.0, 9.0, 19.0); + + assert_eq!(0, rect.top); + assert_eq!(0, rect.left); + assert_eq!(1, rect.bot); + assert_eq!(1, rect.right); } #[test] @@ -409,12 +470,12 @@ mod tests { #[test] fn test_repaint_rect() { let rect = ModelRect::point(1, 1); - let (x, y, width, height) = rect.to_area(10, 5); + let (x, y, width, height) = rect.to_area(10.0, 5.0); assert_eq!(5, x); assert_eq!(10, y); - assert_eq!(5, width); - assert_eq!(10, height); + assert_eq!(4, width); + assert_eq!(9, height); } #[test]