1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

fonts: allow shaping with additional paragraph context

we don't really use this yet, except internally when we do fallback
This commit is contained in:
Wez Furlong 2022-01-27 10:30:35 -07:00
parent c737fb66df
commit 4ca1378f1f
8 changed files with 55 additions and 20 deletions

View File

@ -4,6 +4,7 @@ use freetype;
pub use harfbuzz::*; pub use harfbuzz::*;
use anyhow::{ensure, Error}; use anyhow::{ensure, Error};
use std::ops::Range;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::{mem, slice}; use std::{mem, slice};
@ -121,7 +122,6 @@ impl Buffer {
} }
} }
#[allow(dead_code)]
pub fn set_direction(&mut self, direction: hb_direction_t) { pub fn set_direction(&mut self, direction: hb_direction_t) {
unsafe { unsafe {
hb_buffer_set_direction(self.buf, direction); hb_buffer_set_direction(self.buf, direction);
@ -148,20 +148,24 @@ impl Buffer {
} }
} }
pub fn add_utf8(&mut self, buf: &[u8]) { #[allow(dead_code)]
pub fn reverse(&mut self) {
unsafe { unsafe {
hb_buffer_add_utf8( hb_buffer_reverse_clusters(self.buf);
self.buf,
buf.as_ptr() as *const c_char,
buf.len() as i32,
0,
buf.len() as i32,
);
} }
} }
pub fn add_str(&mut self, s: &str) { pub fn add_str(&mut self, paragraph: &str, range: Range<usize>) {
self.add_utf8(s.as_bytes()) let bytes = paragraph.as_bytes();
unsafe {
hb_buffer_add_utf8(
self.buf,
bytes.as_ptr() as *const c_char,
bytes.len() as i32,
range.start as u32,
(range.end - range.start) as i32,
);
}
} }
/// Returns glyph information. This is only valid after calling /// Returns glyph information. This is only valid after calling

View File

@ -11,6 +11,7 @@ use config::{
use rangeset::RangeSet; use rangeset::RangeSet;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ops::Range;
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::sync::mpsc::{channel, Sender}; use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -116,6 +117,7 @@ impl LoadedFont {
text: &str, text: &str,
presentation: Option<Presentation>, presentation: Option<Presentation>,
direction: Direction, direction: Direction,
range: Option<Range<usize>>,
) -> anyhow::Result<Vec<GlyphInfo>> { ) -> anyhow::Result<Vec<GlyphInfo>> {
loop { loop {
let (tx, rx) = channel(); let (tx, rx) = channel();
@ -128,6 +130,7 @@ impl LoadedFont {
|_| {}, |_| {},
presentation, presentation,
direction, direction,
range.clone(),
) { ) {
Ok(tuple) => tuple, Ok(tuple) => tuple,
Err(err) if err.downcast_ref::<ClearShapeCache>().is_some() => { Err(err) if err.downcast_ref::<ClearShapeCache>().is_some() => {
@ -152,6 +155,7 @@ impl LoadedFont {
filter_out_synthetic: FS, filter_out_synthetic: FS,
presentation: Option<Presentation>, presentation: Option<Presentation>,
direction: Direction, direction: Direction,
range: Option<Range<usize>>,
) -> anyhow::Result<Vec<GlyphInfo>> { ) -> anyhow::Result<Vec<GlyphInfo>> {
let (_async_resolve, res) = self.shape_impl( let (_async_resolve, res) = self.shape_impl(
text, text,
@ -159,6 +163,7 @@ impl LoadedFont {
filter_out_synthetic, filter_out_synthetic,
presentation, presentation,
direction, direction,
range,
)?; )?;
Ok(res) Ok(res)
} }
@ -170,6 +175,7 @@ impl LoadedFont {
filter_out_synthetic: FS, filter_out_synthetic: FS,
presentation: Option<Presentation>, presentation: Option<Presentation>,
direction: Direction, direction: Direction,
range: Option<Range<usize>>,
) -> anyhow::Result<(bool, Vec<GlyphInfo>)> { ) -> anyhow::Result<(bool, Vec<GlyphInfo>)> {
let mut no_glyphs = vec![]; let mut no_glyphs = vec![];
@ -193,6 +199,7 @@ impl LoadedFont {
&mut no_glyphs, &mut no_glyphs,
presentation, presentation,
direction, direction,
range,
); );
no_glyphs.retain(|&c| c != '\u{FE0F}' && c != '\u{FE0E}'); no_glyphs.retain(|&c| c != '\u{FE0F}' && c != '\u{FE0E}');

View File

@ -8,6 +8,7 @@ use log::error;
use ordered_float::NotNan; use ordered_float::NotNan;
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range;
use termwiz::cell::{unicode_column_width, Presentation}; use termwiz::cell::{unicode_column_width, Presentation};
use thiserror::Error; use thiserror::Error;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
@ -187,6 +188,7 @@ impl HarfbuzzShaper {
no_glyphs: &mut Vec<char>, no_glyphs: &mut Vec<char>,
presentation: Option<Presentation>, presentation: Option<Presentation>,
direction: Direction, direction: Direction,
range: Range<usize>,
) -> anyhow::Result<Vec<GlyphInfo>> { ) -> anyhow::Result<Vec<GlyphInfo>> {
let mut buf = harfbuzz::Buffer::new()?; let mut buf = harfbuzz::Buffer::new()?;
// We deliberately omit setting the script and leave it to harfbuzz // We deliberately omit setting the script and leave it to harfbuzz
@ -201,7 +203,7 @@ impl HarfbuzzShaper {
}); });
buf.set_language(self.lang); buf.set_language(self.lang);
buf.add_str(s); buf.add_str(s, range.clone());
let mut cluster_to_len = vec![]; let mut cluster_to_len = vec![];
for c in s.chars() { for c in s.chars() {
let len = c.len_utf8(); let len = c.len_utf8();
@ -288,6 +290,7 @@ impl HarfbuzzShaper {
no_glyphs, no_glyphs,
None, None,
direction, direction,
range,
); );
} }
} }
@ -370,7 +373,8 @@ impl HarfbuzzShaper {
.map(|info| info.cluster + info.len) .map(|info| info.cluster + info.len)
.max() .max()
.unwrap(); .unwrap();
let substr = &s[cluster_start..cluster_end]; let sub_range = cluster_start..cluster_end;
let substr = &s[sub_range.clone()];
let incomplete = infos.iter().find(|info| info.codepoint == 0).is_some(); let incomplete = infos.iter().find(|info| info.codepoint == 0).is_some();
@ -386,12 +390,13 @@ impl HarfbuzzShaper {
let mut shape = match self.do_shape( let mut shape = match self.do_shape(
font_idx + 1, font_idx + 1,
substr, s,
font_size, font_size,
dpi, dpi,
no_glyphs, no_glyphs,
presentation, presentation,
direction, direction,
sub_range.clone(),
) { ) {
Ok(shape) => Ok(shape), Ok(shape) => Ok(shape),
Err(e) => { Err(e) => {
@ -404,14 +409,11 @@ impl HarfbuzzShaper {
no_glyphs, no_glyphs,
presentation, presentation,
direction, direction,
0..substr.len(),
) )
} }
}?; }?;
// Fixup the cluster member to match our current offset
for mut info in &mut shape {
info.cluster += cluster_start as u32;
}
cluster.append(&mut shape); cluster.append(&mut shape);
continue; continue;
} }
@ -485,10 +487,22 @@ impl FontShaper for HarfbuzzShaper {
no_glyphs: &mut Vec<char>, no_glyphs: &mut Vec<char>,
presentation: Option<Presentation>, presentation: Option<Presentation>,
direction: Direction, direction: Direction,
range: Option<Range<usize>>,
) -> anyhow::Result<Vec<GlyphInfo>> { ) -> anyhow::Result<Vec<GlyphInfo>> {
let range = range.unwrap_or_else(|| 0..text.len());
log::trace!("shape byte_len={} `{}`", text.len(), text.escape_debug()); log::trace!("shape byte_len={} `{}`", text.len(), text.escape_debug());
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let result = self.do_shape(0, text, size, dpi, no_glyphs, presentation, direction); let result = self.do_shape(
0,
text,
size,
dpi,
no_glyphs,
presentation,
direction,
range,
);
metrics::histogram!("shape.harfbuzz", start.elapsed()); metrics::histogram!("shape.harfbuzz", start.elapsed());
/* /*
if let Ok(glyphs) = &result { if let Ok(glyphs) = &result {

View File

@ -1,5 +1,6 @@
use crate::parser::ParsedFont; use crate::parser::ParsedFont;
use crate::units::PixelLength; use crate::units::PixelLength;
use std::ops::Range;
use termwiz::cell::Presentation; use termwiz::cell::Presentation;
pub mod harfbuzz; pub mod harfbuzz;
@ -81,6 +82,7 @@ pub trait FontShaper {
no_glyphs: &mut Vec<char>, no_glyphs: &mut Vec<char>,
presentation: Option<termwiz::cell::Presentation>, presentation: Option<termwiz::cell::Presentation>,
direction: Direction, direction: Direction,
range: Option<Range<usize>>,
) -> anyhow::Result<Vec<GlyphInfo>>; ) -> anyhow::Result<Vec<GlyphInfo>>;
/// Compute the font metrics for the preferred font /// Compute the font metrics for the preferred font

View File

@ -688,7 +688,12 @@ pub fn run_ls_fonts(config: config::ConfigHandle, cmd: &LsFontsCommand) -> anyho
let style = font_config.match_style(&config, &cluster.attrs); let style = font_config.match_style(&config, &cluster.attrs);
let font = font_config.resolve_font(style)?; let font = font_config.resolve_font(style)?;
let infos = font let infos = font
.blocking_shape(&cluster.text, Some(cluster.presentation), cluster.direction) .blocking_shape(
&cluster.text,
Some(cluster.presentation),
cluster.direction,
None,
)
.unwrap(); .unwrap();
// We must grab the handles after shaping, so that we get the // We must grab the handles after shaping, so that we get the

View File

@ -547,6 +547,7 @@ impl super::TermWindow {
BlockKey::filter_out_synthetic, BlockKey::filter_out_synthetic,
element.presentation, element.presentation,
direction, direction,
None,
)?; )?;
let mut computed_cells = vec![]; let mut computed_cells = vec![];
let mut glyph_cache = context.gl_state.glyph_cache.borrow_mut(); let mut glyph_cache = context.gl_state.glyph_cache.borrow_mut();

View File

@ -2686,6 +2686,7 @@ impl super::TermWindow {
BlockKey::filter_out_synthetic, BlockKey::filter_out_synthetic,
Some(cluster.presentation), Some(cluster.presentation),
cluster.direction, cluster.direction,
None, // FIXME: need more paragraph context
) { ) {
Ok(info) => { Ok(info) => {
let glyphs = self.glyph_infos_to_glyphs( let glyphs = self.glyph_infos_to_glyphs(

View File

@ -463,6 +463,7 @@ impl ConceptFrame {
}, },
None, None,
wezterm_bidi::Direction::LeftToRight, wezterm_bidi::Direction::LeftToRight,
None,
) )
.ok()?; .ok()?;