Finish area readrawing optimization

This commit is contained in:
daa84 2017-03-21 13:10:55 +03:00
parent 778cbd0af2
commit e676af8f91
2 changed files with 88 additions and 27 deletions

View File

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

View File

@ -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<Cell>,
}
impl <'a> ClipLine<'a> {
pub fn new(model: &'a Vec<Cell>, 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<Cell>,
pos: usize,
iter: Iter<'a, Cell>,
}
@ -327,21 +370,12 @@ pub struct ClipColIterator<'a> {
impl <'a> ClipColIterator<'a> {
pub fn new(model: &'a Vec<Cell>, 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]