diff --git a/wezterm-gui/src/customglyph.rs b/wezterm-gui/src/customglyph.rs index f2134e636..168451b46 100644 --- a/wezterm-gui/src/customglyph.rs +++ b/wezterm-gui/src/customglyph.rs @@ -1,4 +1,4 @@ -use crate::glyphcache::GlyphCache; +use crate::glyphcache::{GlyphCache, SizedBlockKey}; use crate::utilsprites::RenderMetrics; use ::window::bitmaps::atlas::Sprite; use ::window::color::{LinearRgba, SrgbaPixel}; @@ -3661,17 +3661,21 @@ impl GlyphCache { } } - pub fn cursor_sprite(&mut self, shape: Option) -> anyhow::Result> { + pub fn cursor_sprite( + &mut self, + shape: Option, + metrics: &RenderMetrics, + ) -> anyhow::Result> { if let Some(sprite) = self.cursor_glyphs.get(&shape) { return Ok(sprite.clone()); } let mut buffer = Image::new( - self.metrics.cell_size.width as usize, - self.metrics.cell_size.height as usize, + metrics.cell_size.width as usize, + metrics.cell_size.height as usize, ); let black = SrgbaPixel::rgba(0, 0, 0, 0); - let cell_rect = Rect::new(Point::new(0, 0), self.metrics.cell_size); + let cell_rect = Rect::new(Point::new(0, 0), metrics.cell_size); buffer.clear_rect(cell_rect, black); match shape { @@ -3680,7 +3684,6 @@ impl GlyphCache { buffer.clear_rect(cell_rect, SrgbaPixel::rgba(0xff, 0xff, 0xff, 0xff)); } Some(CursorShape::BlinkingBlock | CursorShape::SteadyBlock) => { - let metrics = self.metrics.clone(); self.draw_polys( &metrics, &[Poly { @@ -3698,7 +3701,6 @@ impl GlyphCache { ); } Some(CursorShape::BlinkingBar | CursorShape::SteadyBar) => { - let metrics = self.metrics.clone(); self.draw_polys( &metrics, &[Poly { @@ -3713,7 +3715,6 @@ impl GlyphCache { ); } Some(CursorShape::BlinkingUnderline | CursorShape::SteadyUnderline) => { - let metrics = self.metrics.clone(); self.draw_polys( &metrics, &[Poly { @@ -3734,8 +3735,12 @@ impl GlyphCache { Ok(sprite) } - pub fn block_sprite(&mut self, block: BlockKey) -> anyhow::Result> { - let metrics = match &block { + pub fn block_sprite( + &mut self, + render_metrics: &RenderMetrics, + key: SizedBlockKey, + ) -> anyhow::Result> { + let metrics = match &key.block { BlockKey::PolyWithCustomMetrics { underline_height, cell_size, @@ -3748,7 +3753,7 @@ impl GlyphCache { strike_row: 0, cell_size: cell_size.clone(), }, - _ => self.metrics.clone(), + _ => render_metrics.clone(), }; let mut buffer = Image::new( @@ -3761,7 +3766,7 @@ impl GlyphCache { buffer.clear_rect(cell_rect, black); - match block { + match key.block { BlockKey::Upper(num) => { let lower = metrics.cell_size.height as f32 * (num as f32) / 8.; let width = metrics.cell_size.width as usize; @@ -3916,7 +3921,7 @@ impl GlyphCache { */ let sprite = self.atlas.allocate(&buffer)?; - self.block_glyphs.insert(block, sprite.clone()); + self.block_glyphs.insert(key, sprite.clone()); Ok(sprite) } } diff --git a/wezterm-gui/src/glyphcache.rs b/wezterm-gui/src/glyphcache.rs index 5fe034366..46af4eff2 100644 --- a/wezterm-gui/src/glyphcache.rs +++ b/wezterm-gui/src/glyphcache.rs @@ -27,12 +27,40 @@ use wezterm_font::units::*; use wezterm_font::{FontConfiguration, GlyphInfo, LoadedFont}; use wezterm_term::Underline; +pub fn rc_to_usize(rc: &Rc) -> usize { + Rc::as_ptr(rc) as usize +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct CellMetricKey { + pub pixel_width: u16, + pub pixel_height: u16, +} + +impl From<&RenderMetrics> for CellMetricKey { + fn from(metrics: &RenderMetrics) -> CellMetricKey { + CellMetricKey { + pixel_width: metrics.cell_size.width as u16, + pixel_height: metrics.cell_size.height as u16, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SizedBlockKey { + pub block: BlockKey, + pub size: CellMetricKey, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GlyphKey { pub font_idx: usize, pub glyph_pos: u32, pub style: TextStyle, pub followed_by_space: bool, + pub metric: CellMetricKey, + /// as produced by rc_to_usize + pub font_ptr: usize, } /// We'd like to avoid allocating when resolving from the cache @@ -46,6 +74,9 @@ pub struct BorrowedGlyphKey<'a> { pub glyph_pos: u32, pub style: &'a TextStyle, pub followed_by_space: bool, + pub metric: CellMetricKey, + /// as produced by rc_to_usize + pub font_ptr: usize, } impl<'a> BorrowedGlyphKey<'a> { @@ -55,6 +86,8 @@ impl<'a> BorrowedGlyphKey<'a> { glyph_pos: self.glyph_pos, style: self.style.clone(), followed_by_space: self.followed_by_space, + metric: self.metric, + font_ptr: self.font_ptr, } } } @@ -70,6 +103,8 @@ impl GlyphKeyTrait for GlyphKey { glyph_pos: self.glyph_pos, style: &self.style, followed_by_space: self.followed_by_space, + metric: self.metric, + font_ptr: self.font_ptr, } } } @@ -134,6 +169,7 @@ struct LineKey { strike_through: bool, underline: Underline, overline: bool, + size: CellMetricKey, } /// A helper struct to implement BitmapImage for ImageDataType while @@ -219,19 +255,14 @@ pub struct GlyphCache { pub image_cache: LruCache, frame_cache: HashMap<[u8; 32], Sprite>, line_glyphs: HashMap>, - pub block_glyphs: HashMap>, + pub block_glyphs: HashMap>, pub cursor_glyphs: HashMap, Sprite>, pub color: HashMap<(RgbColor, NotNan), Sprite>, - pub metrics: RenderMetrics, } #[cfg(test)] impl GlyphCache { - pub fn new_in_memory( - fonts: &Rc, - size: usize, - metrics: &RenderMetrics, - ) -> anyhow::Result { + pub fn new_in_memory(fonts: &Rc, size: usize) -> anyhow::Result { let surface = Rc::new(ImageTexture::new(size, size)); let atlas = Atlas::new(&surface).expect("failed to create new texture atlas"); @@ -245,7 +276,6 @@ impl GlyphCache { ), frame_cache: HashMap::new(), atlas, - metrics: metrics.clone(), line_glyphs: HashMap::new(), block_glyphs: HashMap::new(), cursor_glyphs: HashMap::new(), @@ -259,7 +289,6 @@ impl GlyphCache { backend: &Rc, fonts: &Rc, size: usize, - metrics: &RenderMetrics, ) -> anyhow::Result { let caps = backend.get_capabilities(); // You'd hope that allocating a texture would automatically @@ -298,7 +327,6 @@ impl GlyphCache { ), frame_cache: HashMap::new(), atlas, - metrics: metrics.clone(), line_glyphs: HashMap::new(), block_glyphs: HashMap::new(), cursor_glyphs: HashMap::new(), @@ -315,13 +343,16 @@ impl GlyphCache { info: &GlyphInfo, style: &TextStyle, followed_by_space: bool, - font: Option<&Rc>, + font: &Rc, + metrics: &RenderMetrics, ) -> anyhow::Result>> { let key = BorrowedGlyphKey { font_idx: info.font_idx, glyph_pos: info.glyph_pos, style, followed_by_space, + metric: metrics.into(), + font_ptr: rc_to_usize(font), }; if let Some(entry) = self.glyph_cache.get(&key as &dyn GlyphKeyTrait) { @@ -330,7 +361,7 @@ impl GlyphCache { } metrics::histogram!("glyph_cache.glyph_cache.miss.rate", 1.); - let glyph = match self.load_glyph(info, style, font, followed_by_space) { + let glyph = match self.load_glyph(info, font, followed_by_space) { Ok(g) => g, Err(err) => { if err @@ -374,8 +405,7 @@ impl GlyphCache { fn load_glyph( &mut self, info: &GlyphInfo, - style: &TextStyle, - font: Option<&Rc>, + font: &Rc, followed_by_space: bool, ) -> anyhow::Result>> { let base_metrics; @@ -384,10 +414,6 @@ impl GlyphCache { let glyph; { - let font = match font { - Some(f) => Rc::clone(f), - None => self.fonts.resolve_font(style)?, - }; base_metrics = font.metrics(); glyph = font.rasterize_glyph(info.glyph_pos, info.font_idx)?; @@ -660,33 +686,41 @@ impl GlyphCache { Ok(sprite) } - pub fn cached_block(&mut self, block: BlockKey) -> anyhow::Result> { - if let Some(s) = self.block_glyphs.get(&block) { + pub fn cached_block( + &mut self, + block: BlockKey, + metrics: &RenderMetrics, + ) -> anyhow::Result> { + let key = SizedBlockKey { + block, + size: metrics.into(), + }; + if let Some(s) = self.block_glyphs.get(&key) { return Ok(s.clone()); } - self.block_sprite(block) + self.block_sprite(metrics, key) } - fn line_sprite(&mut self, key: LineKey) -> anyhow::Result> { + fn line_sprite(&mut self, key: LineKey, metrics: &RenderMetrics) -> anyhow::Result> { let mut buffer = Image::new( - self.metrics.cell_size.width as usize, - self.metrics.cell_size.height as usize, + metrics.cell_size.width as usize, + metrics.cell_size.height as usize, ); let black = SrgbaPixel::rgba(0, 0, 0, 0); let white = SrgbaPixel::rgba(0xff, 0xff, 0xff, 0xff); - let cell_rect = Rect::new(Point::new(0, 0), self.metrics.cell_size); + let cell_rect = Rect::new(Point::new(0, 0), metrics.cell_size); let draw_single = |buffer: &mut Image| { - for row in 0..self.metrics.underline_height { + for row in 0..metrics.underline_height { buffer.draw_line( Point::new( cell_rect.origin.x, - cell_rect.origin.y + self.metrics.descender_row + row, + cell_rect.origin.y + metrics.descender_row + row, ), Point::new( - cell_rect.origin.x + self.metrics.cell_size.width, - cell_rect.origin.y + self.metrics.descender_row + row, + cell_rect.origin.x + metrics.cell_size.width, + cell_rect.origin.y + metrics.descender_row + row, ), white, ); @@ -694,17 +728,17 @@ impl GlyphCache { }; let draw_dotted = |buffer: &mut Image| { - for row in 0..self.metrics.underline_height { - let y = (cell_rect.origin.y + self.metrics.descender_row + row) as usize; - if y >= self.metrics.cell_size.height as usize { + for row in 0..metrics.underline_height { + let y = (cell_rect.origin.y + metrics.descender_row + row) as usize; + if y >= metrics.cell_size.height as usize { break; } let mut color = white; - let segment_length = (self.metrics.cell_size.width / 4) as usize; + let segment_length = (metrics.cell_size.width / 4) as usize; let mut count = segment_length; let range = - buffer.horizontal_pixel_range_mut(0, self.metrics.cell_size.width as usize, y); + buffer.horizontal_pixel_range_mut(0, metrics.cell_size.width as usize, y); for c in range.iter_mut() { *c = color.as_srgba32(); count -= 1; @@ -717,16 +751,16 @@ impl GlyphCache { }; let draw_dashed = |buffer: &mut Image| { - for row in 0..self.metrics.underline_height { - let y = (cell_rect.origin.y + self.metrics.descender_row + row) as usize; - if y >= self.metrics.cell_size.height as usize { + for row in 0..metrics.underline_height { + let y = (cell_rect.origin.y + metrics.descender_row + row) as usize; + if y >= metrics.cell_size.height as usize { break; } let mut color = white; - let third = (self.metrics.cell_size.width / 3) as usize + 1; + let third = (metrics.cell_size.width / 3) as usize + 1; let mut count = third; let range = - buffer.horizontal_pixel_range_mut(0, self.metrics.cell_size.width as usize, y); + buffer.horizontal_pixel_range_mut(0, metrics.cell_size.width as usize, y); for c in range.iter_mut() { *c = color.as_srgba32(); count -= 1; @@ -739,16 +773,15 @@ impl GlyphCache { }; let draw_curly = |buffer: &mut Image| { - let max_y = self.metrics.cell_size.height as usize - 1; - let x_factor = (2. * std::f32::consts::PI) / self.metrics.cell_size.width as f32; + let max_y = metrics.cell_size.height as usize - 1; + let x_factor = (2. * std::f32::consts::PI) / metrics.cell_size.width as f32; // Have the wave go from the descender to the bottom of the cell let wave_height = - self.metrics.cell_size.height - (cell_rect.origin.y + self.metrics.descender_row); + metrics.cell_size.height - (cell_rect.origin.y + metrics.descender_row); let half_height = (wave_height as f32 / 4.).max(1.); - let y = - (cell_rect.origin.y + self.metrics.descender_row) as usize - half_height as usize; + let y = (cell_rect.origin.y + metrics.descender_row) as usize - half_height as usize; fn add(x: usize, y: usize, val: u8, max_y: usize, buffer: &mut Image) { let y = y.min(max_y); @@ -758,12 +791,12 @@ impl GlyphCache { *pixel = SrgbaPixel::rgba(value, value, value, value).as_srgba32(); } - for x in 0..self.metrics.cell_size.width as usize { + for x in 0..metrics.cell_size.width as usize { let vertical = -half_height * (x as f32 * x_factor).sin() + half_height; let v1 = vertical.floor(); let v2 = vertical.ceil(); - for row in 0..self.metrics.underline_height as usize { + for row in 0..metrics.underline_height as usize { let value = (255. * (vertical - v1).abs()) as u8; add(x, row + y + v1 as usize, 255 - value, max_y, buffer); add(x, row + y + v2 as usize, value, max_y, buffer); @@ -772,16 +805,15 @@ impl GlyphCache { }; let draw_double = |buffer: &mut Image| { - let first_line = self - .metrics + let first_line = metrics .descender_row - .min(self.metrics.descender_plus_two - 2 * self.metrics.underline_height); + .min(metrics.descender_plus_two - 2 * metrics.underline_height); - for row in 0..self.metrics.underline_height { + for row in 0..metrics.underline_height { buffer.draw_line( Point::new(cell_rect.origin.x, cell_rect.origin.y + first_line + row), Point::new( - cell_rect.origin.x + self.metrics.cell_size.width, + cell_rect.origin.x + metrics.cell_size.width, cell_rect.origin.y + first_line + row, ), white, @@ -789,11 +821,11 @@ impl GlyphCache { buffer.draw_line( Point::new( cell_rect.origin.x, - cell_rect.origin.y + self.metrics.descender_plus_two + row, + cell_rect.origin.y + metrics.descender_plus_two + row, ), Point::new( - cell_rect.origin.x + self.metrics.cell_size.width, - cell_rect.origin.y + self.metrics.descender_plus_two + row, + cell_rect.origin.x + metrics.cell_size.width, + cell_rect.origin.y + metrics.descender_plus_two + row, ), white, ); @@ -801,15 +833,15 @@ impl GlyphCache { }; let draw_strike = |buffer: &mut Image| { - for row in 0..self.metrics.underline_height { + for row in 0..metrics.underline_height { buffer.draw_line( Point::new( cell_rect.origin.x, - cell_rect.origin.y + self.metrics.strike_row + row, + cell_rect.origin.y + metrics.strike_row + row, ), Point::new( - cell_rect.origin.x + self.metrics.cell_size.width, - cell_rect.origin.y + self.metrics.strike_row + row, + cell_rect.origin.x + metrics.cell_size.width, + cell_rect.origin.y + metrics.strike_row + row, ), white, ); @@ -817,11 +849,11 @@ impl GlyphCache { }; let draw_overline = |buffer: &mut Image| { - for row in 0..self.metrics.underline_height { + for row in 0..metrics.underline_height { buffer.draw_line( Point::new(cell_rect.origin.x, cell_rect.origin.y + row), Point::new( - cell_rect.origin.x + self.metrics.cell_size.width, + cell_rect.origin.x + metrics.cell_size.width, cell_rect.origin.y + row, ), white, @@ -858,6 +890,7 @@ impl GlyphCache { is_strike_through: bool, underline: Underline, overline: bool, + metrics: &RenderMetrics, ) -> anyhow::Result> { let effective_underline = match (is_highlited_hyperlink, underline) { (true, Underline::None) => Underline::Single, @@ -870,12 +903,13 @@ impl GlyphCache { strike_through: is_strike_through, overline, underline: effective_underline, + size: metrics.into(), }; if let Some(s) = self.line_glyphs.get(&key) { return Ok(s.clone()); } - self.line_sprite(key) + self.line_sprite(key, metrics) } } diff --git a/wezterm-gui/src/renderstate.rs b/wezterm-gui/src/renderstate.rs index 5d341a24b..ef90c2d3c 100644 --- a/wezterm-gui/src/renderstate.rs +++ b/wezterm-gui/src/renderstate.rs @@ -118,8 +118,7 @@ impl RenderState { mut atlas_size: usize, ) -> anyhow::Result { loop { - let glyph_cache = - RefCell::new(GlyphCache::new_gl(&context, fonts, atlas_size, metrics)?); + let glyph_cache = RefCell::new(GlyphCache::new_gl(&context, fonts, atlas_size)?); let result = UtilSprites::new(&mut *glyph_cache.borrow_mut(), metrics); match result { Ok(util_sprites) => { @@ -291,7 +290,7 @@ impl RenderState { size: Option, ) -> anyhow::Result<()> { let size = size.unwrap_or_else(|| self.glyph_cache.borrow().atlas.size()); - let mut new_glyph_cache = GlyphCache::new_gl(&self.context, fonts, size, metrics)?; + let mut new_glyph_cache = GlyphCache::new_gl(&self.context, fonts, size)?; self.util_sprites = UtilSprites::new(&mut new_glyph_cache, metrics)?; let mut glyph_cache = self.glyph_cache.borrow_mut(); diff --git a/wezterm-gui/src/shapecache.rs b/wezterm-gui/src/shapecache.rs index 1aea69f07..ce718ce28 100644 --- a/wezterm-gui/src/shapecache.rs +++ b/wezterm-gui/src/shapecache.rs @@ -288,7 +288,7 @@ mod test { }; glyph_cache - .cached_glyph(info, &style, followed_by_space, None) + .cached_glyph(info, &style, followed_by_space, font, render_metrics) .unwrap() }) .collect::>(); @@ -331,7 +331,7 @@ mod test { .unwrap(), ); let render_metrics = RenderMetrics::new(&fonts).unwrap(); - let mut glyph_cache = GlyphCache::new_in_memory(&fonts, 128, &render_metrics).unwrap(); + let mut glyph_cache = GlyphCache::new_in_memory(&fonts, 128).unwrap(); let style = TextStyle::default(); let font = fonts.resolve_font(&style).unwrap(); @@ -416,7 +416,7 @@ mod test { .unwrap(), ); let render_metrics = RenderMetrics::new(&fonts).unwrap(); - let mut glyph_cache = GlyphCache::new_in_memory(&fonts, 128, &render_metrics).unwrap(); + let mut glyph_cache = GlyphCache::new_in_memory(&fonts, 128).unwrap(); let style = TextStyle::default(); let font = fonts.resolve_font(&style).unwrap(); diff --git a/wezterm-gui/src/termwindow/render.rs b/wezterm-gui/src/termwindow/render.rs index e1bf87e8e..4419d7c05 100644 --- a/wezterm-gui/src/termwindow/render.rs +++ b/wezterm-gui/src/termwindow/render.rs @@ -9,6 +9,7 @@ use crate::termwindow::{ BorrowedShapeCacheKey, MappedQuads, RenderState, ScrollHit, ShapedInfo, TermWindowNotif, UIItem, UIItemType, }; +use crate::utilsprites::RenderMetrics; use ::window::bitmaps::atlas::OutOfTextureSpace; use ::window::bitmaps::{TextureCoord, TextureRect, TextureSize}; use ::window::glium; @@ -21,6 +22,7 @@ use anyhow::anyhow; use config::{ ConfigHandle, DimensionContext, HsbTransform, TabBarColors, TextStyle, VisualBellTarget, }; +use euclid::num::Zero; use mux::pane::Pane; use mux::renderable::{RenderableDimensions, StableCursorPosition}; use mux::tab::{PositionedPane, PositionedSplit, SplitDirection}; @@ -31,7 +33,7 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use termwiz::cell::{unicode_column_width, Blink}; use termwiz::cellcluster::CellCluster; use termwiz::surface::{CursorShape, CursorVisibility}; -use wezterm_font::units::IntPixelLength; +use wezterm_font::units::{IntPixelLength, PixelLength}; use wezterm_font::{ClearShapeCache, FontMetrics, GlyphInfo, LoadedFont}; use wezterm_term::color::{ColorAttribute, ColorPalette, RgbColor}; use wezterm_term::{CellAttributes, Line, StableRowIndex}; @@ -80,6 +82,8 @@ pub struct RenderScreenLineOpenGLParams<'a> { /// rather than using monospace cell based positions. pub use_pixel_positioning: bool, pub pre_shaped: Option<&'a Vec>>, + + pub render_metrics: RenderMetrics, } pub struct ComputeCellFgBgParams<'a> { @@ -347,11 +351,14 @@ impl super::TermWindow { let sprite = gl_state .glyph_cache .borrow_mut() - .cached_block(BlockKey::PolyWithCustomMetrics { - polys, - underline_height, - cell_size, - })? + .cached_block( + BlockKey::PolyWithCustomMetrics { + polys, + underline_height, + cell_size, + }, + &self.render_metrics, + )? .texture_coords(); let mut quad = layer.allocate()?; @@ -509,6 +516,7 @@ impl super::TermWindow { style: Some(&self.config.window_frame.font), use_pixel_positioning: true, pre_shaped: None, + render_metrics: RenderMetrics::with_font_metrics(metrics), }; let cell_clusters = item.title.cluster(); let shaped = self.cluster_and_shape(&cell_clusters, ¶ms)?; @@ -689,6 +697,7 @@ impl super::TermWindow { )) } TabBarItem::None => { + // log::info!("{:#?}", shaped); // Right align to window width let tab_bounding_rect: Rect = euclid::rect( tab_bounding_rect.min_x(), @@ -941,6 +950,7 @@ impl super::TermWindow { font: None, use_pixel_positioning: false, pre_shaped: None, + render_metrics: self.render_metrics, }, &mut layers, )?; @@ -1290,6 +1300,7 @@ impl super::TermWindow { style: None, use_pixel_positioning: false, pre_shaped: None, + render_metrics: self.render_metrics, }, &mut layers, )?; @@ -1458,7 +1469,7 @@ impl super::TermWindow { let sprite = gl_state .glyph_cache .borrow_mut() - .cached_block(block)? + .cached_block(block, &self.render_metrics)? .texture_coords(); let mut quad = quads.allocate()?; @@ -1578,6 +1589,7 @@ impl super::TermWindow { attrs.strikethrough(), attrs.underline(), attrs.overline(), + ¶ms.render_metrics, )? .texture_coords(); let bg_is_default = attrs.background() == ColorAttribute::Default; @@ -1670,6 +1682,7 @@ impl super::TermWindow { &gl_state, params.line, params.font.as_ref(), + ¶ms.render_metrics, )?; let pixel_width = glyph_info .iter() @@ -1709,14 +1722,8 @@ impl super::TermWindow { Some(params.config.inactive_pane_hsb) }; - let metrics = params.font.as_ref().map(|f| f.metrics()); - - let cell_width = metrics - .map(|m| m.cell_width.get() as isize) - .unwrap_or(self.render_metrics.cell_size.width) as f32; - let cell_height = metrics - .map(|m| m.cell_height.get() as isize) - .unwrap_or(self.render_metrics.cell_size.height) as f32; + let cell_width = params.render_metrics.cell_size.width as f32; + let cell_height = params.render_metrics.cell_size.height as f32; let pos_y = (self.dimensions.pixel_height as f32 / -2.) + params.top_pixel_y; let start = Instant::now(); @@ -1855,7 +1862,7 @@ impl super::TermWindow { .texture .as_ref() .map(|t| { - let width = self.render_metrics.cell_size.width as f32; + let width = params.render_metrics.cell_size.width as f32; if t.coords.size.width as f32 > width * 1.5 { // Glyph is wider than the cell true @@ -1869,11 +1876,7 @@ impl super::TermWindow { .unwrap_or(false); */ - let top = cell_height - + (metrics - .map(|m| m.descender) - .unwrap_or(self.render_metrics.descender) - .get() as f32) + let top = cell_height + params.render_metrics.descender.get() as f32 - (glyph.y_offset + glyph.bearing_y).get() as f32; // We use this to remember the `left` offset value to use for glyph_idx > 0 @@ -2012,7 +2015,7 @@ impl super::TermWindow { gl_state .glyph_cache .borrow_mut() - .cursor_sprite(cursor_shape)? + .cursor_sprite(cursor_shape, ¶ms.render_metrics)? .texture_coords(), ); @@ -2070,7 +2073,7 @@ impl super::TermWindow { block, gl_state, &mut layers[0], - cell_idx, + pos_x, ¶ms, hsv, glyph_color, @@ -2119,7 +2122,7 @@ impl super::TermWindow { let slice = SpriteSlice { cell_idx: glyph_idx, num_cells: info.pos.num_cells as usize, - cell_width: self.render_metrics.cell_size.width as usize, + cell_width: params.render_metrics.cell_size.width as usize, scale: glyph.scale as f32, left_offset: left, }; @@ -2131,9 +2134,9 @@ impl super::TermWindow { let left = if glyph_idx == 0 { left } else { slice_left }; let bottom = (pixel_rect.size.height as f32 * glyph.scale as f32) + top - - self.render_metrics.cell_size.height as f32; + - params.render_metrics.cell_size.height as f32; let right = pixel_rect.size.width as f32 + left - - self.render_metrics.cell_size.width as f32; + - params.render_metrics.cell_size.width as f32; // Save the `right` position; we'll use it for the `left` adjust for // the next slice that comprises this glyph. @@ -2285,7 +2288,7 @@ impl super::TermWindow { gl_state .glyph_cache .borrow_mut() - .cursor_sprite(cursor_shape)? + .cursor_sprite(cursor_shape, ¶ms.render_metrics)? .texture_coords(), ); quad.set_fg_color(cursor_border_color); @@ -2312,7 +2315,7 @@ impl super::TermWindow { block: BlockKey, gl_state: &RenderState, quads: &mut MappedQuads, - cell_idx: usize, + pos_x: f32, params: &RenderScreenLineOpenGLParams, hsv: Option, glyph_color: LinearRgba, @@ -2320,16 +2323,13 @@ impl super::TermWindow { let sprite = gl_state .glyph_cache .borrow_mut() - .cached_block(block)? + .cached_block(block, ¶ms.render_metrics)? .texture_coords(); let mut quad = quads.allocate()?; - let cell_width = self.render_metrics.cell_size.width as f32; - let cell_height = self.render_metrics.cell_size.height as f32; + let cell_width = params.render_metrics.cell_size.width as f32; + let cell_height = params.render_metrics.cell_size.height as f32; let pos_y = (self.dimensions.pixel_height as f32 / -2.) + params.top_pixel_y; - let pos_x = (self.dimensions.pixel_width as f32 / -2.) - + params.left_pixel_x - + (cell_idx as f32 * cell_width); quad.set_position(pos_x, pos_y, pos_x + cell_width, pos_y + cell_height); quad.set_hsv(hsv); quad.set_fg_color(glyph_color); @@ -2358,7 +2358,7 @@ impl super::TermWindow { .render_metrics .cell_size .height - .max(self.render_metrics.cell_size.width) as usize; + .max(params.render_metrics.cell_size.width) as usize; let padding = if padding.is_power_of_two() { padding } else { @@ -2396,8 +2396,8 @@ impl super::TermWindow { let texture_rect = TextureRect::new(origin, size); let mut quad = quads.allocate()?; - let cell_width = self.render_metrics.cell_size.width as f32; - let cell_height = self.render_metrics.cell_size.height as f32; + let cell_width = params.render_metrics.cell_size.width as f32; + let cell_height = params.render_metrics.cell_size.height as f32; let pos_y = (self.dimensions.pixel_height as f32 / -2.) + params.top_pixel_y; let pos_x = (self.dimensions.pixel_width as f32 / -2.) @@ -2580,17 +2580,47 @@ impl super::TermWindow { style: &TextStyle, glyph_cache: &mut GlyphCache, infos: &[GlyphInfo], - font: Option<&Rc>, + font: &Rc, + metrics: &RenderMetrics, ) -> anyhow::Result>>> { let mut glyphs = Vec::with_capacity(infos.len()); for info in infos { let cell_idx = cluster.byte_to_cell_idx(info.cluster as usize); + + if self.config.custom_block_glyphs { + if let Some(cell) = line.cells().get(cell_idx) { + if BlockKey::from_cell(cell).is_some() { + // Don't bother rendering the glyph from the font, as it can + // have incorrect advance metrics. + // Instead, just use our pixel-perfect cell metrics + glyphs.push(Rc::new(CachedGlyph { + brightness_adjust: 1.0, + has_color: false, + texture: None, + x_advance: PixelLength::new(metrics.cell_size.width as f64), + x_offset: PixelLength::zero(), + y_offset: PixelLength::zero(), + bearing_x: PixelLength::zero(), + bearing_y: PixelLength::zero(), + scale: 1.0, + })); + continue; + } + } + } + let followed_by_space = match line.cells().get(cell_idx + 1) { Some(cell) => cell.str() == " ", None => false, }; - glyphs.push(glyph_cache.cached_glyph(info, &style, followed_by_space, font)?); + glyphs.push(glyph_cache.cached_glyph( + info, + &style, + followed_by_space, + font, + metrics, + )?); } Ok(glyphs) } @@ -2603,6 +2633,7 @@ impl super::TermWindow { gl_state: &RenderState, line: &Line, font: Option<&Rc>, + metrics: &RenderMetrics, ) -> anyhow::Result>>> { let shape_resolve_start = Instant::now(); let key = BorrowedShapeCacheKey { @@ -2631,14 +2662,10 @@ impl super::TermWindow { &style, &mut gl_state.glyph_cache.borrow_mut(), &info, - Some(&font), + &font, + metrics, )?; - let shaped = Rc::new(ShapedInfo::process( - &self.render_metrics, - cluster, - &info, - &glyphs, - )); + let shaped = Rc::new(ShapedInfo::process(metrics, cluster, &info, &glyphs)); self.shape_cache .borrow_mut() diff --git a/wezterm-gui/src/utilsprites.rs b/wezterm-gui/src/utilsprites.rs index 7e3186011..f948c0a2d 100644 --- a/wezterm-gui/src/utilsprites.rs +++ b/wezterm-gui/src/utilsprites.rs @@ -6,7 +6,7 @@ use ::window::{Point, Rect, Size}; use anyhow::Context; use std::rc::Rc; use wezterm_font::units::*; -use wezterm_font::FontConfiguration; +use wezterm_font::{FontConfiguration, FontMetrics}; #[derive(Copy, Clone, Debug)] pub struct RenderMetrics { @@ -19,6 +19,30 @@ pub struct RenderMetrics { } impl RenderMetrics { + pub fn with_font_metrics(metrics: &FontMetrics) -> Self { + let (cell_height, cell_width) = ( + metrics.cell_height.get().ceil() as usize, + metrics.cell_width.get().ceil() as usize, + ); + + let underline_height = metrics.underline_thickness.get().round().max(1.) as isize; + + let descender_row = + (cell_height as f64 + (metrics.descender - metrics.underline_position).get()) as isize; + let descender_plus_two = + (2 * underline_height + descender_row).min(cell_height as isize - underline_height); + let strike_row = descender_row / 2; + + Self { + descender: metrics.descender, + descender_row, + descender_plus_two, + strike_row, + cell_size: Size::new(cell_width as isize, cell_height as isize), + underline_height, + } + } + pub fn new(fonts: &Rc) -> anyhow::Result { let metrics = fonts .default_font_metrics()