aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/renderer/rects.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/renderer/rects.rs')
-rw-r--r--alacritty/src/renderer/rects.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
new file mode 100644
index 00000000..5bc353ff
--- /dev/null
+++ b/alacritty/src/renderer/rects.rs
@@ -0,0 +1,149 @@
+// 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 font::Metrics;
+
+use alacritty_terminal::index::{Column, Point};
+use alacritty_terminal::term::cell::Flags;
+use alacritty_terminal::term::color::Rgb;
+use alacritty_terminal::term::{RenderableCell, SizeInfo};
+
+#[derive(Debug, Copy, Clone)]
+pub struct RenderRect {
+ pub x: f32,
+ pub y: f32,
+ pub width: f32,
+ pub height: f32,
+ pub color: Rgb,
+ pub alpha: f32,
+}
+
+impl RenderRect {
+ pub fn new(x: f32, y: f32, width: f32, height: f32, color: Rgb, alpha: f32) -> Self {
+ RenderRect { x, y, width, height, color, alpha }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct RenderLine {
+ pub start: Point,
+ pub end: Point,
+ pub color: Rgb,
+}
+
+impl RenderLine {
+ pub fn rects(&self, flag: Flags, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> {
+ let mut rects = Vec::new();
+
+ let mut start = self.start;
+ while start.line < self.end.line {
+ let mut end = start;
+ end.col = size.cols() - 1;
+ rects.push(Self::create_rect(metrics, size, flag, start, end, self.color));
+
+ start.col = Column(0);
+ start.line += 1;
+ }
+
+ rects.push(Self::create_rect(metrics, size, flag, start, self.end, self.color));
+
+ rects
+ }
+
+ fn create_rect(
+ metrics: &Metrics,
+ size: &SizeInfo,
+ flag: Flags,
+ start: Point,
+ end: Point,
+ color: Rgb,
+ ) -> RenderRect {
+ let start_x = start.col.0 as f32 * size.cell_width;
+ let end_x = (end.col.0 + 1) as f32 * size.cell_width;
+ let width = end_x - start_x;
+
+ let (position, mut 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"),
+ };
+
+ // Make sure lines are always visible
+ height = height.max(1.);
+
+ let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height;
+ let baseline = line_bottom + metrics.descent;
+
+ let mut y = baseline - position - height / 2.;
+ let max_y = line_bottom - height;
+ if y > max_y {
+ y = max_y;
+ }
+
+ RenderRect::new(start_x + size.padding_x, y + size.padding_y, width, height, color, 1.)
+ }
+}
+
+/// Lines for underline and strikeout.
+#[derive(Default)]
+pub struct RenderLines {
+ inner: HashMap<Flags, Vec<RenderLine>>,
+}
+
+impl RenderLines {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn rects(&self, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> {
+ self.inner
+ .iter()
+ .map(|(flag, lines)| -> Vec<RenderRect> {
+ lines.iter().map(|line| line.rects(*flag, metrics, size)).flatten().collect()
+ })
+ .flatten()
+ .collect()
+ }
+
+ /// Update the stored lines with the next cell info.
+ pub fn update(&mut self, cell: RenderableCell) {
+ for flag in &[Flags::UNDERLINE, Flags::STRIKEOUT] {
+ if !cell.flags.contains(*flag) {
+ continue;
+ }
+
+ // Check if there's an active line
+ if let Some(line) = self.inner.get_mut(flag).and_then(|lines| lines.last_mut()) {
+ if cell.fg == line.color
+ && cell.column == line.end.col + 1
+ && cell.line == line.end.line
+ {
+ // Update the length of the line
+ line.end = cell.into();
+ continue;
+ }
+ }
+
+ // Start new line if there currently is none
+ let line = RenderLine { start: cell.into(), end: cell.into(), color: cell.fg };
+ match self.inner.get_mut(flag) {
+ Some(lines) => lines.push(line),
+ None => {
+ self.inner.insert(*flag, vec![line]);
+ },
+ }
+ }
+ }
+}