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