Fix multiple underlines/strikeouts on the same line

This commit fixes regression introduced in ddee14a.
This commit is contained in:
Kirill Chibisov 2019-08-07 01:46:02 +03:00 committed by Christian Duerr
parent 14fa02648e
commit b20d285782
3 changed files with 58 additions and 66 deletions

View File

@ -27,7 +27,7 @@ use crate::config::{Config, StartupMode};
use crate::index::Line; use crate::index::Line;
use crate::message_bar::Message; use crate::message_bar::Message;
use crate::meter::Meter; use crate::meter::Meter;
use crate::renderer::rects::{Rect, Rects}; use crate::renderer::rects::{RenderRect, RenderLines};
use crate::renderer::{self, GlyphCache, QuadRenderer}; use crate::renderer::{self, GlyphCache, QuadRenderer};
use crate::sync::FairMutex; use crate::sync::FairMutex;
use crate::term::color::Rgb; use crate::term::color::Rgb;
@ -511,7 +511,7 @@ impl Display {
{ {
let glyph_cache = &mut self.glyph_cache; let glyph_cache = &mut self.glyph_cache;
let mut rects = Rects::new(); let mut lines = RenderLines::new();
// Draw grid // Draw grid
{ {
@ -521,7 +521,7 @@ impl Display {
// Iterate over all non-empty cells in the grid // Iterate over all non-empty cells in the grid
for cell in grid_cells { for cell in grid_cells {
// Update underline/strikeout // Update underline/strikeout
rects.update_lines(&cell, &size_info, &metrics); lines.update(&cell);
// Draw the cell // Draw the cell
api.render_cell(cell, glyph_cache); api.render_cell(cell, glyph_cache);
@ -529,14 +529,21 @@ impl Display {
}); });
} }
let mut rects = lines.into_rects(&metrics, &size_info);
if let Some(message) = message_buffer { if let Some(message) = message_buffer {
let text = message.text(&size_info); let text = message.text(&size_info);
// Create a new rectangle for the background // Create a new rectangle for the background
let start_line = size_info.lines().0 - text.len(); let start_line = size_info.lines().0 - text.len();
let y = size_info.padding_y + size_info.cell_height * start_line as f32; let y = size_info.padding_y + size_info.cell_height * start_line as f32;
let rect = Rect::new(0., y, size_info.width, size_info.height - y); rects.push(RenderRect::new(
rects.push(rect, message.color()); 0.,
y,
size_info.width,
size_info.height - y,
message.color(),
));
// Draw rectangles including the new background // Draw rectangles including the new background
self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects); self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects);

View File

@ -31,7 +31,7 @@ use crate::cursor::{get_cursor_glyph, CursorKey};
use crate::gl; use crate::gl;
use crate::gl::types::*; use crate::gl::types::*;
use crate::index::{Column, Line}; use crate::index::{Column, Line};
use crate::renderer::rects::{Rect, Rects}; use crate::renderer::rects::RenderRect;
use crate::term::color::Rgb; use crate::term::color::Rgb;
use crate::term::{self, cell, RenderableCell, RenderableCellContent}; use crate::term::{self, cell, RenderableCell, RenderableCellContent};
@ -679,7 +679,7 @@ impl QuadRenderer {
config: &Config, config: &Config,
props: &term::SizeInfo, props: &term::SizeInfo,
visual_bell_intensity: f64, visual_bell_intensity: f64,
cell_line_rects: Rects, cell_line_rects: Vec<RenderRect>,
) { ) {
// Swap to rectangle rendering program // Swap to rectangle rendering program
unsafe { unsafe {
@ -710,12 +710,12 @@ impl QuadRenderer {
// Draw visual bell // Draw visual bell
let color = config.visual_bell.color; let color = config.visual_bell.color;
let rect = Rect::new(0., 0., props.width, props.height); let rect = RenderRect::new(0., 0., props.width, props.height, color);
self.render_rect(&rect, color, visual_bell_intensity as f32, props); self.render_rect(&rect, visual_bell_intensity as f32, props);
// Draw underlines and strikeouts // Draw underlines and strikeouts
for cell_line_rect in cell_line_rects.rects() { for cell_line_rect in cell_line_rects {
self.render_rect(&cell_line_rect.0, cell_line_rect.1, 255., props); self.render_rect(&cell_line_rect, 255., props);
} }
// Deactivate rectangle program again // Deactivate rectangle program again
@ -849,7 +849,7 @@ impl QuadRenderer {
// Render a rectangle // Render a rectangle
// //
// This requires the rectangle program to be activated // This requires the rectangle program to be activated
fn render_rect(&mut self, rect: &Rect<f32>, color: Rgb, alpha: f32, size: &term::SizeInfo) { fn render_rect(&mut self, rect: &RenderRect, alpha: f32, size: &term::SizeInfo) {
// Do nothing when alpha is fully transparent // Do nothing when alpha is fully transparent
if alpha == 0. { if alpha == 0. {
return; return;
@ -876,7 +876,7 @@ impl QuadRenderer {
); );
// Color // Color
self.rect_program.set_color(color, alpha); self.rect_program.set_color(rect.color, alpha);
// Draw the rectangle // Draw the rectangle
gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null()); gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());

View File

@ -21,29 +21,31 @@ use crate::term::color::Rgb;
use crate::term::{RenderableCell, SizeInfo}; use crate::term::{RenderableCell, SizeInfo};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Rect<T> { pub struct RenderRect {
pub x: T, pub x: f32,
pub y: T, pub y: f32,
pub width: T, pub width: f32,
pub height: T, pub height: f32,
pub color: Rgb,
} }
impl<T> Rect<T> { impl RenderRect {
pub fn new(x: T, y: T, width: T, height: T) -> Self { pub fn new(x: f32, y: f32, width: f32, height: f32, color: Rgb) -> Self {
Rect { x, y, width, height } RenderRect { x, y, width, height, color }
} }
} }
struct Line { struct RenderLine {
rect: Rect<f32>,
start: Point, start: Point,
end: Point,
color: Rgb, color: Rgb,
} }
impl Line { impl RenderLine {
/// Create a line that starts on the left of `cell` and is one cell wide fn into_rect(self, flag: Flags, metrics: &Metrics, size: &SizeInfo) -> RenderRect {
fn from_cell(cell: &RenderableCell, flag: Flags, metrics: &Metrics, size: &SizeInfo) -> Line { let start_x = self.start.col.0 as f32 * size.cell_width;
let cell_x = cell.column.0 as f32 * size.cell_width; let end_x = (self.end.col.0 + 1) as f32 * size.cell_width;
let width = end_x - start_x;
let (position, mut height) = match flag { let (position, mut height) = match flag {
Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness), Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness),
@ -54,48 +56,42 @@ impl Line {
// Make sure lines are always visible // Make sure lines are always visible
height = height.max(1.); height = height.max(1.);
let cell_bottom = (cell.line.0 as f32 + 1.) * size.cell_height; let line_bottom = (self.start.line.0 as f32 + 1.) * size.cell_height;
let baseline = cell_bottom + metrics.descent; let baseline = line_bottom + metrics.descent;
let mut y = baseline - position - height / 2.; let mut y = baseline - position - height / 2.;
let max_y = cell_bottom - height; let max_y = line_bottom - height;
if y > max_y { if y > max_y {
y = max_y; y = max_y;
} }
let rect = Rect::new(cell_x + size.padding_x, y + size.padding_y, size.cell_width, height); RenderRect::new(start_x + size.padding_x, y + size.padding_y, width, height, self.color)
Self { start: cell.into(), color: cell.fg, rect }
}
fn update_end(&mut self, end: Point, size: &SizeInfo) {
self.rect.width = (end.col + 1 - self.start.col).0 as f32 * size.cell_width;
} }
} }
/// Rects for underline, strikeout and more. /// Lines for underline and strikeout.
#[derive(Default)] #[derive(Default)]
pub struct Rects { pub struct RenderLines {
inner: HashMap<Flags, Vec<Line>>, inner: HashMap<Flags, Vec<RenderLine>>,
} }
impl Rects { impl RenderLines {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Convert the stored rects to rectangles for the renderer. pub fn into_rects(self, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> {
pub fn rects(&self) -> Vec<(Rect<f32>, Rgb)> {
self.inner self.inner
.iter() .into_iter()
.map(|(_, lines)| lines) .map(|(flag, lines)| -> Vec<RenderRect> {
lines.into_iter().map(|line| line.into_rect(flag, &metrics, &size)).collect()
})
.flatten() .flatten()
.map(|line| (line.rect, line.color))
.collect() .collect()
} }
/// Update the stored lines with the next cell info. /// Update the stored lines with the next cell info.
pub fn update_lines(&mut self, cell: &RenderableCell, size: &SizeInfo, metrics: &Metrics) { pub fn update(&mut self, cell: &RenderableCell) {
for flag in &[Flags::UNDERLINE, Flags::STRIKEOUT] { for flag in &[Flags::UNDERLINE, Flags::STRIKEOUT] {
if !cell.flags.contains(*flag) { if !cell.flags.contains(*flag) {
continue; continue;
@ -103,35 +99,24 @@ impl Rects {
// Check if there's an active line // Check if there's an active line
if let Some(line) = self.inner.get_mut(flag).and_then(|lines| lines.last_mut()) { if let Some(line) = self.inner.get_mut(flag).and_then(|lines| lines.last_mut()) {
if cell.line == line.start.line && cell.fg == line.color { if cell.line == line.start.line
&& cell.fg == line.color
&& cell.column == line.end.col + 1
{
// Update the length of the line // Update the length of the line
line.update_end(cell.into(), size); line.end = cell.into();
continue; continue;
} }
} }
// Start new line if there currently is none // Start new line if there currently is none
let rect = Line::from_cell(cell, *flag, metrics, size); let line = RenderLine { start: cell.into(), end: cell.into(), color: cell.fg };
match self.inner.get_mut(flag) { match self.inner.get_mut(flag) {
Some(lines) => lines.push(rect), Some(lines) => lines.push(line),
None => { None => {
self.inner.insert(*flag, vec![rect]); self.inner.insert(*flag, vec![line]);
}, },
} }
} }
} }
// Add a rectangle
pub fn push(&mut self, rect: Rect<f32>, color: Rgb) {
let line = Line { start: Point::default(), color, rect };
// Flag `HIDDEN` for hashmap index is arbitrary
match self.inner.get_mut(&Flags::HIDDEN) {
Some(lines) => lines.push(line),
None => {
self.inner.insert(Flags::HIDDEN, vec![line]);
},
}
}
} }