From 837fcb7b45b9413140d27a9659635283604ccc96 Mon Sep 17 00:00:00 2001 From: daa84 Date: Fri, 8 Sep 2017 18:26:16 +0300 Subject: [PATCH] Fix redraw clip rect calculation --- src/render/context.rs | 6 ++++ src/render/mod.rs | 2 +- src/shell.rs | 11 +++++-- src/ui_model/item.rs | 67 ++++++++++++++++++++++++++++++++++---- src/ui_model/line.rs | 2 +- src/ui_model/model_rect.rs | 56 +++++++++++++++++++------------ 6 files changed, 111 insertions(+), 33 deletions(-) diff --git a/src/render/context.rs b/src/render/context.rs index 5149008..046cd5b 100644 --- a/src/render/context.rs +++ b/src/render/context.rs @@ -69,11 +69,17 @@ pub struct CellMetrics { pub line_height: f64, pub char_width: f64, pub ascent: f64, + pub pango_ascent: i32, + pub pango_descent: i32, + pub pango_char_width: i32, } impl CellMetrics { fn new(font_metrics: &pango::FontMetrics) -> Self { CellMetrics { + pango_ascent: font_metrics.get_ascent(), + pango_descent: font_metrics.get_descent(), + pango_char_width: font_metrics.get_approximate_digit_width(), ascent: font_metrics.get_ascent() as f64 / pango::SCALE as f64, line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) as f64 / pango::SCALE as f64, diff --git a/src/render/mod.rs b/src/render/mod.rs index 43e8057..4601566 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -119,7 +119,7 @@ pub fn shape_dirty( ); } - item.set_glyphs(glyphs); + item.set_glyphs(ctx, glyphs); } } diff --git a/src/shell.rs b/src/shell.rs index 0d51172..011f4da 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -176,11 +176,16 @@ impl State { } fn queue_draw_area>(&mut self, rect_list: &[M]) { - //FIXME: extends by items before, then after + // extends by items before, then after changes + + let rects: Vec<_> = rect_list.iter().map(|rect| rect.as_ref().clone()).map(|mut rect| { + rect.extend_by_items(&self.model); + rect + }).collect(); + self.update_dirty_glyphs(); - for rect in rect_list { - let mut rect = rect.as_ref().clone(); + for mut rect in rects { rect.extend_by_items(&self.model); let (x, y, width, height) = diff --git a/src/ui_model/item.rs b/src/ui_model/item.rs index c528ee0..b470c4a 100644 --- a/src/ui_model/item.rs +++ b/src/ui_model/item.rs @@ -1,3 +1,4 @@ +use render; use sys::pango as sys_pango; use pango; @@ -5,18 +6,22 @@ use pango; #[derive(Clone)] pub struct Item { pub item: sys_pango::Item, + pub cells_count: usize, pub glyphs: Option, - pub ink_rect: Option, + pub ink_overflow: Option, font: pango::Font, } impl Item { - pub fn new(item: sys_pango::Item) -> Self { + pub fn new(item: sys_pango::Item, cells_count: usize) -> Self { + debug_assert!(cells_count > 0); + Item { font: item.analysis().font(), item, + cells_count, glyphs: None, - ink_rect: None, + ink_overflow: None, } } @@ -24,14 +29,13 @@ impl Item { self.font = item.analysis().font(); self.item = item; self.glyphs = None; - self.ink_rect = None; + self.ink_overflow = None; } - pub fn set_glyphs(&mut self, glyphs: pango::GlyphString) { + pub fn set_glyphs(&mut self, ctx: &render::Context, glyphs: pango::GlyphString) { let mut glyphs = glyphs; - // FIXME: pango units let (ink_rect, _) = glyphs.extents(&self.font); - self.ink_rect = Some(ink_rect); + self.ink_overflow = InkOverflow::from(ctx, &ink_rect, self.cells_count as i32); self.glyphs = Some(glyphs); } @@ -43,3 +47,52 @@ impl Item { self.item.analysis() } } + +#[derive(Clone)] +pub struct InkOverflow { + pub left: f64, + pub right: f64, + pub top: f64, + pub bot: f64, +} + +impl InkOverflow { + pub fn from( + ctx: &render::Context, + ink_rect: &pango::Rectangle, + cells_count: i32, + ) -> Option { + let cell_metrix = ctx.cell_metrics(); + + let ink_descent = ink_rect.y + ink_rect.height; + let ink_ascent = ink_rect.y.abs(); + + let mut top = ink_ascent - cell_metrix.pango_ascent; + if top < 0 { + top = 0; + } + + let mut bot = ink_descent - cell_metrix.pango_descent; + if bot < 0 { + bot = 0; + } + + let left = if ink_rect.x < 0 { ink_rect.x.abs() } else { 0 }; + + let mut right = ink_rect.width - cells_count * cell_metrix.pango_char_width; + if right < 0 { + right = 0; + } + + if left == 0 && right == 0 && top == 0 && right == 0 { + None + } else { + Some(InkOverflow { + left: left as f64 / pango::SCALE as f64, + right: right as f64 / pango::SCALE as f64, + top: top as f64 / pango::SCALE as f64, + bot: bot as f64 / pango::SCALE as f64, + }) + } + } +} diff --git a/src/ui_model/line.rs b/src/ui_model/line.rs index df039b7..b3b2cd6 100644 --- a/src/ui_model/line.rs +++ b/src/ui_model/line.rs @@ -160,7 +160,7 @@ impl Line { for i in start_cell + 1..end_cell + 1 { self.item_line[i] = None; } - self.item_line[start_cell] = Some(Item::new(new_item.clone())); + self.item_line[start_cell] = Some(Item::new(new_item.clone(), end_cell - start_cell + 1)); } pub fn mark_dirty_cell(&mut self, idx: usize) { diff --git a/src/ui_model/model_rect.rs b/src/ui_model/model_rect.rs index bca4701..3e95751 100644 --- a/src/ui_model/model_rect.rs +++ b/src/ui_model/model_rect.rs @@ -128,59 +128,73 @@ impl ModelRect { fn extend_left_right_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) { let x = self.left as i32 * cell_metrics.char_width as i32; - let mut x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32; - let mut min_x_offset = 0; + let x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32; + let mut min_x_offset = 0.0; + let mut max_x_offset = 0.0; for row in self.top..self.bot + 1 { - // FIXME: use original, not extended rect here // left let line = &model.model[row]; - if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(self.left) { - if ink_rect.x < min_x_offset { - min_x_offset = x; + if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = + line.item_line[self.left].as_ref() + { + if min_x_offset < overflow.left { + min_x_offset = overflow.left; } } // right let line = &model.model[row]; - if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(self.right) { - let ink_x = x + ink_rect.x + ink_rect.width; - if x2 < ink_x { - x2 = ink_x; + // check if this item ends here + if self.right < model.columns - 1 && + line.cell_to_item(self.right) != line.cell_to_item(self.right + 1) + { + if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = + line.get_item(self.left) + { + if max_x_offset < overflow.right { + max_x_offset = overflow.right; + } } } } - (x + min_x_offset, x2) + ( + x - min_x_offset.ceil() as i32, + x2 + max_x_offset.ceil() as i32, + ) } fn extend_top_bottom_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) { let y = self.top as i32 * cell_metrics.line_height as i32; - let mut y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32; - let mut min_y_offset = 0; + let y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32; + let mut min_y_offset = 0.0; + let mut max_y_offset = 0.0; for col in self.left..self.right + 1 { // top let line = &model.model[self.top]; - if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(col) { - if ink_rect.y < min_y_offset { - min_y_offset = ink_rect.y; + if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) { + if min_y_offset < overflow.top { + min_y_offset = overflow.top; } } // bottom let line = &model.model[self.bot]; - if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(col) { - let ink_y = y + ink_rect.y + ink_rect.height; - if y2 < ink_y { - y2 = ink_y; + if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) { + if max_y_offset < overflow.top { + max_y_offset = overflow.top; } } } - (y + min_y_offset, y2) + ( + y - min_y_offset.ceil() as i32, + y2 + max_y_offset.ceil() as i32, + ) } pub fn join(&mut self, rect: &ModelRect) {