mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +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:
parent
c737fb66df
commit
4ca1378f1f
@ -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
|
||||||
|
@ -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}');
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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(
|
||||||
|
@ -463,6 +463,7 @@ impl ConceptFrame {
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
wezterm_bidi::Direction::LeftToRight,
|
wezterm_bidi::Direction::LeftToRight,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user