summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ansi.rs4
-rw-r--r--src/display.rs16
-rw-r--r--src/renderer/lines.rs143
-rw-r--r--src/renderer/mod.rs124
-rw-r--r--src/term/cell.rs23
-rw-r--r--src/term/mod.rs4
6 files changed, 229 insertions, 85 deletions
diff --git a/src/ansi.rs b/src/ansi.rs
index db8022e2..29b1a459 100644
--- a/src/ansi.rs
+++ b/src/ansi.rs
@@ -642,7 +642,7 @@ pub enum Attr {
Reverse,
/// Do not display characters
Hidden,
- /// Strikethrough text
+ /// Strikeout text
Strike,
/// Cancel bold
CancelBold,
@@ -658,7 +658,7 @@ pub enum Attr {
CancelReverse,
/// Cancel text hiding
CancelHidden,
- /// Cancel strike through
+ /// Cancel strikeout
CancelStrike,
/// Set indexed foreground color
Foreground(Color),
diff --git a/src/display.rs b/src/display.rs
index 120cd1dc..b1575c58 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -25,6 +25,7 @@ use crate::config::Config;
use font::{self, Rasterize};
use crate::meter::Meter;
use crate::renderer::{self, GlyphCache, QuadRenderer};
+use crate::renderer::lines::Lines;
use crate::term::{Term, SizeInfo, RenderableCell};
use crate::sync::FairMutex;
use crate::window::{self, Window};
@@ -410,19 +411,27 @@ impl Display {
{
let glyph_cache = &mut self.glyph_cache;
+ let metrics = glyph_cache.font_metrics();
+ let mut cell_line_rects = Lines::new(&metrics, &size_info);
// Draw grid
{
let _sampler = self.meter.sampler();
self.renderer.with_api(config, &size_info, |mut api| {
- // Draw the grid
- api.render_cells(grid_cells.iter(), glyph_cache);
+ // Iterate over all non-empty cells in the grid
+ for cell in grid_cells {
+ // Update underline/strikeout
+ cell_line_rects.update_lines(&cell);
+
+ // Draw the cell
+ api.render_cell(cell, glyph_cache);
+ }
});
}
// Draw rectangles
- self.renderer.draw_rects(config, &size_info, visual_bell_intensity);
+ self.renderer.draw_rects(config, &size_info, visual_bell_intensity, cell_line_rects);
// Draw render timer
if self.render_timer {
@@ -490,4 +499,3 @@ impl Display {
self.window().set_ime_spot(LogicalPosition::from((nspot_x, nspot_y)));
}
}
-
diff --git a/src/renderer/lines.rs b/src/renderer/lines.rs
new file mode 100644
index 00000000..556dcb0d
--- /dev/null
+++ b/src/renderer/lines.rs
@@ -0,0 +1,143 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use std::collections::HashMap;
+
+use crate::term::{ SizeInfo, RenderableCell};
+use crate::term::cell::Flags;
+use crate::renderer::Rect;
+use font::Metrics;
+use crate::Rgb;
+
+/// Lines for underline and strikeout.
+pub struct Lines<'a> {
+ inner: Vec<(Rect<f32>, Rgb)>,
+ last_starts: HashMap<Flags, Option<RenderableCell>>,
+ last_cell: Option<RenderableCell>,
+ metrics: &'a Metrics,
+ size: &'a SizeInfo,
+}
+
+impl<'a> Lines<'a> {
+ pub fn new(metrics: &'a Metrics, size: &'a SizeInfo) -> Self {
+ let mut last_starts = HashMap::new();
+ last_starts.insert(Flags::UNDERLINE, None);
+ last_starts.insert(Flags::STRIKEOUT, None);
+
+ Self {
+ inner: Vec::new(),
+ last_cell: None,
+ last_starts,
+ metrics,
+ size,
+ }
+ }
+
+ /// Convert the stored lines to rectangles for the renderer.
+ pub fn rects(mut self) -> Vec<(Rect<f32>, Rgb)> {
+ // If there's still a line pending, draw it until the last cell
+ for (flag, start_cell) in self.last_starts.iter_mut() {
+ if let Some(start) = start_cell {
+ self.inner.push(
+ create_rect(
+ &start,
+ &self.last_cell.unwrap(),
+ *flag,
+ &self.metrics,
+ &self.size,
+ )
+ );
+ }
+ }
+
+ self.inner
+ }
+
+ /// Update the stored lines with the next cell info.
+ pub fn update_lines(&mut self, cell: &RenderableCell) {
+ for (flag, start_cell) in self.last_starts.iter_mut() {
+ let flag = *flag;
+ *start_cell = match *start_cell {
+ // Check for end if line is present
+ Some(ref mut start) => {
+ // No change in line
+ if cell.line == start.line && cell.flags.contains(flag) && cell.fg == start.fg {
+ continue;
+ }
+
+ self.inner.push(
+ create_rect(
+ &start,
+ &self.last_cell.unwrap(),
+ flag,
+ &self.metrics,
+ &self.size,
+ )
+ );
+
+ // Start a new line if the flag is present
+ if cell.flags.contains(flag) {
+ Some(*cell)
+ } else {
+ None
+ }
+ }
+ // Check for new start of line
+ None => if cell.flags.contains(flag) {
+ Some(*cell)
+ } else {
+ None
+ },
+ };
+ }
+
+ self.last_cell = Some(*cell);
+ }
+}
+
+/// Create a rectangle between two cells.
+fn create_rect(
+ start: &RenderableCell,
+ end: &RenderableCell,
+ flag: Flags,
+ metrics: &Metrics,
+ size: &SizeInfo,
+) -> (Rect<f32>, Rgb) {
+ let start_x = start.column.0 as f32 * size.cell_width;
+ let end_x = (end.column.0 + 1) as f32 * size.cell_width;
+ let width = end_x - start_x;
+
+ let (position, height) = match flag {
+ Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness),
+ Flags::STRIKEOUT => (metrics.strikeout_position, metrics.strikeout_thickness),
+ _ => unimplemented!("Invalid flag for cell line drawing specified"),
+ };
+
+ let cell_bottom = (start.line.0 as f32 + 1.) * size.cell_height;
+ let baseline = cell_bottom + metrics.descent;
+
+ let mut y = baseline - position - height / 2.;
+ let max_y = cell_bottom - height;
+ if y > max_y {
+ y = max_y;
+ }
+
+ let rect = Rect::new(
+ start_x + size.padding_x,
+ y + size.padding_y,
+ width,
+ height,
+ );
+
+ (rect, start.fg)
+}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index c05301cc..42a17486 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -23,16 +23,19 @@ use std::time::Duration;
use cgmath;
use fnv::FnvHasher;
+use glutin::dpi::PhysicalSize;
use font::{self, FontDesc, FontKey, GlyphKey, Rasterize, RasterizedGlyph, Rasterizer};
+use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
+
use crate::gl::types::*;
use crate::gl;
use crate::index::{Column, Line, RangeInclusive};
-use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use crate::Rgb;
-
use crate::config::{self, Config, Delta};
use crate::term::{self, cell, RenderableCell};
-use glutin::dpi::PhysicalSize;
+use crate::renderer::lines::Lines;
+
+pub mod lines;
// Shader paths for live reload
static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl");
@@ -699,6 +702,7 @@ impl QuadRenderer {
config: &Config,
props: &term::SizeInfo,
visual_bell_intensity: f64,
+ cell_line_rects: Lines,
) {
// Swap to rectangle rendering program
unsafe {
@@ -725,6 +729,11 @@ impl QuadRenderer {
let rect = Rect::new(0., 0., props.width, props.height);
self.render_rect(&rect, color, visual_bell_intensity as f32, props);
+ // Draw underlines and strikeouts
+ for cell_line_rect in cell_line_rects.rects() {
+ self.render_rect(&cell_line_rect.0, cell_line_rect.1, 255., props);
+ }
+
// Deactivate rectangle program again
unsafe {
// Reset blending strategy
@@ -902,7 +911,8 @@ impl QuadRenderer {
}
}
-struct Rect<T> {
+#[derive(Debug, Copy, Clone)]
+pub struct Rect<T> {
x: T,
y: T,
width: T,
@@ -910,7 +920,7 @@ struct Rect<T> {
}
impl<T> Rect<T> {
- fn new(x: T, y: T, width: T, height: T) -> Self {
+ pub fn new(x: T, y: T, width: T, height: T) -> Self {
Rect { x, y, width, height }
}
}
@@ -998,7 +1008,9 @@ impl<'a> RenderApi<'a> {
})
.collect::<Vec<_>>();
- self.render_cells(cells.iter(), glyph_cache);
+ for cell in cells {
+ self.render_cell(cell, glyph_cache);
+ }
}
#[inline]
@@ -1016,74 +1028,52 @@ impl<'a> RenderApi<'a> {
}
}
- pub fn render_cells<'b, I>(
- &mut self,
- cells: I,
- glyph_cache: &mut GlyphCache
- )
- where I: Iterator<Item=&'b RenderableCell>
- {
- for cell in cells {
- // Get font key for cell
- // FIXME this is super inefficient.
- let font_key = if cell.flags.contains(cell::Flags::BOLD) {
- glyph_cache.bold_key
- } else if cell.flags.contains(cell::Flags::ITALIC) {
- glyph_cache.italic_key
- } else {
- glyph_cache.font_key
- };
-
- // Don't render text of HIDDEN cells
- let mut chars = if cell.flags.contains(cell::Flags::HIDDEN) {
- [' '; cell::MAX_ZEROWIDTH_CHARS + 1]
- } else {
- cell.chars
- };
+ pub fn render_cell(&mut self, cell: RenderableCell, glyph_cache: &mut GlyphCache) {
+ // Get font key for cell
+ // FIXME this is super inefficient.
+ let font_key = if cell.flags.contains(cell::Flags::BOLD) {
+ glyph_cache.bold_key
+ } else if cell.flags.contains(cell::Flags::ITALIC) {
+ glyph_cache.italic_key
+ } else {
+ glyph_cache.font_key
+ };
- // Render tabs as spaces in case the font doesn't support it
- if chars[0] == '\t' {
- chars[0] = ' ';
- }
+ // Don't render text of HIDDEN cells
+ let mut chars = if cell.flags.contains(cell::Flags::HIDDEN) {
+ [' '; cell::MAX_ZEROWIDTH_CHARS + 1]
+ } else {
+ cell.chars
+ };
- let mut glyph_key = GlyphKey {
- font_key,
- size: glyph_cache.font_size,
- c: chars[0],
- };
+ // Render tabs as spaces in case the font doesn't support it
+ if chars[0] == '\t' {
+ chars[0] = ' ';
+ }
- // Add cell to batch
- let glyph = glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, glyph);
+ let mut glyph_key = GlyphKey {
+ font_key,
+ size: glyph_cache.font_size,
+ c: chars[0],
+ };
- // Render zero-width characters
- for c in (&chars[1..]).iter().filter(|c| **c != ' ') {
- glyph_key.c = *c;
- let mut glyph = *glyph_cache.get(glyph_key, self);
+ // Add cell to batch
+ let glyph = glyph_cache.get(glyph_key, self);
+ self.add_render_item(&cell, glyph);
- // The metrics of zero-width characters are based on rendering
- // the character after the current cell, with the anchor at the
- // right side of the preceding character. Since we render the
- // zero-width characters inside the preceding character, the
- // anchor has been moved to the right by one cell.
- glyph.left += glyph_cache.metrics.average_advance as f32;
+ // Render zero-width characters
+ for c in (&chars[1..]).iter().filter(|c| **c != ' ') {
+ glyph_key.c = *c;
+ let mut glyph = *glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, &glyph);
- }
+ // The metrics of zero-width characters are based on rendering
+ // the character after the current cell, with the anchor at the
+ // right side of the preceding character. Since we render the
+ // zero-width characters inside the preceding character, the
+ // anchor has been moved to the right by one cell.
+ glyph.left += glyph_cache.metrics.average_advance as f32;
- // FIXME This is a super hacky way to do underlined text. During
- // a time crunch to release 0.1, this seemed like a really
- // easy, clean hack.
- if cell.flags.contains(cell::Flags::UNDERLINE) {
- let glyph_key = GlyphKey {
- font_key,
- size: glyph_cache.font_size,
- c: '_',
- };
-
- let underscore = glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, underscore);
- }
+ self.add_render_item(&cell, &glyph);
}
}
}
diff --git a/src/term/cell.rs b/src/term/cell.rs
index bd561482..5d3b7036 100644
--- a/src/term/cell.rs
+++ b/src/term/cell.rs
@@ -23,16 +23,17 @@ pub const MAX_ZEROWIDTH_CHARS: usize = 5;
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct Flags: u16 {
- const INVERSE = 0b0_0000_0001;
- const BOLD = 0b0_0000_0010;
- const ITALIC = 0b0_0000_0100;
- const UNDERLINE = 0b0_0000_1000;
- const WRAPLINE = 0b0_0001_0000;
- const WIDE_CHAR = 0b0_0010_0000;
- const WIDE_CHAR_SPACER = 0b0_0100_0000;
- const DIM = 0b0_1000_0000;
- const DIM_BOLD = 0b0_1000_0010;
- const HIDDEN = 0b1_0000_0000;
+ const INVERSE = 0b00_0000_0001;
+ const BOLD = 0b00_0000_0010;
+ const ITALIC = 0b00_0000_0100;
+ const UNDERLINE = 0b00_0000_1000;
+ const WRAPLINE = 0b00_0001_0000;
+ const WIDE_CHAR = 0b00_0010_0000;
+ const WIDE_CHAR_SPACER = 0b00_0100_0000;
+ const DIM = 0b00_1000_0000;
+ const DIM_BOLD = 0b00_1000_0010;
+ const HIDDEN = 0b01_0000_0000;
+ const STRIKEOUT = 0b10_0000_0000;
}
}
@@ -117,7 +118,7 @@ impl Cell {
(self.c == ' ' || self.c == '\t')
&& self.extra[0] == ' '
&& self.bg == Color::Named(NamedColor::Background)
- && !self.flags.intersects(Flags::INVERSE | Flags::UNDERLINE)
+ && !self.flags.intersects(Flags::INVERSE | Flags::UNDERLINE | Flags::STRIKEOUT)
}
#[inline]
diff --git a/src/term/mod.rs b/src/term/mod.rs
index fd2fcf88..bb65fba6 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -419,7 +419,7 @@ impl<'a> RenderableCellsIter<'a> {
}
}
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct RenderableCell {
/// A _Display_ line (not necessarily an _Active_ line)
pub line: Line,
@@ -1965,6 +1965,8 @@ impl ansi::Handler for Term {
Attr::CancelUnderline => self.cursor.template.flags.remove(cell::Flags::UNDERLINE),
Attr::Hidden => self.cursor.template.flags.insert(cell::Flags::HIDDEN),
Attr::CancelHidden => self.cursor.template.flags.remove(cell::Flags::HIDDEN),
+ Attr::Strike => self.cursor.template.flags.insert(cell::Flags::STRIKEOUT),
+ Attr::CancelStrike => self.cursor.template.flags.remove(cell::Flags::STRIKEOUT),
_ => {
debug!("Term got unhandled attr: {:?}", attr);
}