Fix redraw clip rect calculation

This commit is contained in:
daa84 2017-09-08 18:26:16 +03:00
parent a00d1ff65c
commit 837fcb7b45
6 changed files with 111 additions and 33 deletions

View File

@ -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,

View File

@ -119,7 +119,7 @@ pub fn shape_dirty(
);
}
item.set_glyphs(glyphs);
item.set_glyphs(ctx, glyphs);
}
}

View File

@ -176,11 +176,16 @@ impl State {
}
fn queue_draw_area<M: AsRef<ModelRect>>(&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) =

View File

@ -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<pango::GlyphString>,
pub ink_rect: Option<pango::Rectangle>,
pub ink_overflow: Option<InkOverflow>,
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<Self> {
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,
})
}
}
}

View File

@ -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) {

View File

@ -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) {