mirror of
https://github.com/wez/wezterm.git
synced 2024-12-26 23:04:49 +03:00
improve rendering of emoji
We were scaling some of them down way too much, so use a simpler scaling computation. In addition, try to "crop" the glyph to the non-transparent bits. This seems to improve the visible size of some single-width glyphs that don't fully occupy the bitmap size.
This commit is contained in:
parent
ff20499a09
commit
4098931e62
@ -134,30 +134,88 @@ impl Font for FontImpl {
|
|||||||
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
|
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
|
||||||
let width = ft_glyph.bitmap.width as usize;
|
let width = ft_glyph.bitmap.width as usize;
|
||||||
let height = ft_glyph.bitmap.rows as usize;
|
let height = ft_glyph.bitmap.rows as usize;
|
||||||
let size = (width * height * 4) as usize;
|
|
||||||
let mut rgba = Vec::with_capacity(size);
|
// emoji glyphs don't always fill the bitmap size, so we compute
|
||||||
rgba.resize(size, 0u8);
|
// the non-transparent bounds here with this simplistic code.
|
||||||
|
// This can likely be improved!
|
||||||
|
|
||||||
|
let mut first_line = None;
|
||||||
|
let mut first_col = None;
|
||||||
|
let mut last_col = None;
|
||||||
|
let mut last_line = None;
|
||||||
|
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
let src_offset = y * pitch as usize;
|
let src_offset = y * pitch as usize;
|
||||||
let dest_offset = y * width * 4;
|
|
||||||
for x in 0..width {
|
for x in 0..width {
|
||||||
|
let alpha = data[src_offset + (x * 4) + 3];
|
||||||
|
if alpha != 0 {
|
||||||
|
if first_line.is_none() {
|
||||||
|
first_line = Some(y);
|
||||||
|
}
|
||||||
|
first_col = match first_col.take() {
|
||||||
|
Some(other) if x < other => Some(x),
|
||||||
|
Some(other) => Some(other),
|
||||||
|
None => Some(x),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for y in (0..height).rev() {
|
||||||
|
let src_offset = y * pitch as usize;
|
||||||
|
|
||||||
|
for x in (0..width).rev() {
|
||||||
|
let alpha = data[src_offset + (x * 4) + 3];
|
||||||
|
if alpha != 0 {
|
||||||
|
if last_line.is_none() {
|
||||||
|
last_line = Some(y);
|
||||||
|
}
|
||||||
|
last_col = match last_col.take() {
|
||||||
|
Some(other) if x > other => Some(x),
|
||||||
|
Some(other) => Some(other),
|
||||||
|
None => Some(x),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let first_line = first_line.unwrap_or(0);
|
||||||
|
let last_line = last_line.unwrap_or(0);
|
||||||
|
let first_col = first_col.unwrap_or(0);
|
||||||
|
let last_col = last_col.unwrap_or(0);
|
||||||
|
|
||||||
|
let dest_width = 1 + last_col - first_col;
|
||||||
|
let dest_height = 1 + last_line - first_line;
|
||||||
|
|
||||||
|
let size = (dest_width * dest_height * 4) as usize;
|
||||||
|
let mut rgba = Vec::with_capacity(size);
|
||||||
|
rgba.resize(size, 0u8);
|
||||||
|
|
||||||
|
for y in first_line..=last_line {
|
||||||
|
let src_offset = y * pitch as usize;
|
||||||
|
let dest_offset = (y - first_line) * dest_width * 4;
|
||||||
|
for x in first_col..=last_col {
|
||||||
let blue = data[src_offset + (x * 4)];
|
let blue = data[src_offset + (x * 4)];
|
||||||
let green = data[src_offset + (x * 4) + 1];
|
let green = data[src_offset + (x * 4) + 1];
|
||||||
let red = data[src_offset + (x * 4) + 2];
|
let red = data[src_offset + (x * 4) + 2];
|
||||||
let alpha = data[src_offset + (x * 4) + 3];
|
let alpha = data[src_offset + (x * 4) + 3];
|
||||||
|
|
||||||
rgba[dest_offset + (x * 4)] = red;
|
let dest_x = x - first_col;
|
||||||
rgba[dest_offset + (x * 4) + 1] = green;
|
|
||||||
rgba[dest_offset + (x * 4) + 2] = blue;
|
rgba[dest_offset + (dest_x * 4)] = red;
|
||||||
rgba[dest_offset + (x * 4) + 3] = alpha;
|
rgba[dest_offset + (dest_x * 4) + 1] = green;
|
||||||
|
rgba[dest_offset + (dest_x * 4) + 2] = blue;
|
||||||
|
rgba[dest_offset + (dest_x * 4) + 3] = alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RasterizedGlyph {
|
RasterizedGlyph {
|
||||||
data: rgba,
|
data: rgba,
|
||||||
height,
|
height: dest_height,
|
||||||
width,
|
width: dest_width,
|
||||||
bearing_x: ft_glyph.bitmap_left,
|
bearing_x: (ft_glyph.bitmap_left as f64 * (dest_width as f64 / width as f64))
|
||||||
bearing_y: ft_glyph.bitmap_top,
|
as i32,
|
||||||
|
bearing_y: (ft_glyph.bitmap_top as f64 * (dest_height as f64 / height as f64))
|
||||||
|
as i32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
|
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
|
||||||
|
@ -441,7 +441,7 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Perform the load and render of a glyph
|
/// Perform the load and render of a glyph
|
||||||
fn load_glyph(&self, info: &GlyphInfo, style: &TextStyle) -> Result<Rc<CachedGlyph>, Error> {
|
fn load_glyph(&self, info: &GlyphInfo, style: &TextStyle) -> Result<Rc<CachedGlyph>, Error> {
|
||||||
let (has_color, glyph, cell_width, cell_height) = {
|
let (has_color, glyph, cell_width, _cell_height) = {
|
||||||
let font = self.fonts.cached_font(style)?;
|
let font = self.fonts.cached_font(style)?;
|
||||||
let mut font = font.borrow_mut();
|
let mut font = font.borrow_mut();
|
||||||
let metrics = font.get_fallback(0)?.metrics();
|
let metrics = font.get_fallback(0)?.metrics();
|
||||||
@ -451,13 +451,14 @@ impl Renderer {
|
|||||||
(has_color, glyph, metrics.cell_width, metrics.cell_height)
|
(has_color, glyph, metrics.cell_width, metrics.cell_height)
|
||||||
};
|
};
|
||||||
|
|
||||||
let scale = if (info.x_advance / f64::from(info.num_cells)).floor() > cell_width {
|
let effective_width = f64::from(info.num_cells) * cell_width;
|
||||||
f64::from(info.num_cells) * (cell_width / info.x_advance)
|
|
||||||
} else if glyph.height as f64 > cell_height {
|
let scale = if glyph.width as f64 > effective_width {
|
||||||
cell_height / glyph.height as f64
|
effective_width / glyph.width as f64
|
||||||
} else {
|
} else {
|
||||||
1.0f64
|
1.0f64
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
#[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
||||||
let (x_offset, y_offset) = if scale != 1.0 {
|
let (x_offset, y_offset) = if scale != 1.0 {
|
||||||
(info.x_offset * scale, info.y_offset * scale)
|
(info.x_offset * scale, info.y_offset * scale)
|
||||||
|
Loading…
Reference in New Issue
Block a user