mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +03:00
zeno -> tiny_skia
Mostly so that we can turn off anti-aliasing for smaller sizes, but it also happens to be more complete anyway.
This commit is contained in:
parent
fad09eddda
commit
4c0d789ac3
37
Cargo.lock
generated
37
Cargo.lock
generated
@ -120,6 +120,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
@ -3654,6 +3660,15 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "safe_arch"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -4301,6 +4316,20 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bf81f2900d2e235220e6f31ec9f63ade6a7f59090c556d74fe949bb3b15e9fe"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if 1.0.0",
|
||||
"png",
|
||||
"safe_arch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.2.0"
|
||||
@ -4915,6 +4944,7 @@ dependencies = [
|
||||
"termwiz",
|
||||
"textwrap 0.14.0",
|
||||
"thiserror",
|
||||
"tiny-skia",
|
||||
"umask",
|
||||
"unicode-normalization",
|
||||
"unicode-segmentation",
|
||||
@ -4931,7 +4961,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
"window",
|
||||
"windows",
|
||||
"zeno",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5421,12 +5450,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeno"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea708573d4a67f939793b0d3f923d105bfdf06bbd6acb3f9cd02ce1bd905f6c8"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.6.1+zstd.1.4.9"
|
||||
|
@ -57,6 +57,7 @@ terminfo = "0.7"
|
||||
termwiz = { path = "../termwiz" }
|
||||
textwrap = "0.14"
|
||||
thiserror = "1.0"
|
||||
tiny-skia = "0.5"
|
||||
umask = { path = "../umask" }
|
||||
unicode-normalization = "0.1"
|
||||
unicode-segmentation = "1.7"
|
||||
@ -71,7 +72,6 @@ wezterm-ssh = { path = "../wezterm-ssh" }
|
||||
wezterm-term = { path = "../term", features=["use_serde"] }
|
||||
wezterm-toast-notification = { path = "../wezterm-toast-notification" }
|
||||
window = { path = "../window" }
|
||||
zeno = "0.2"
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
shared_library = "0.1"
|
||||
|
@ -18,10 +18,10 @@ use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use termwiz::image::ImageData;
|
||||
use tiny_skia::{FillRule, Paint, Path, PathBuilder, PixmapMut, Stroke, Transform};
|
||||
use wezterm_font::units::*;
|
||||
use wezterm_font::{FontConfiguration, GlyphInfo};
|
||||
use wezterm_term::Underline;
|
||||
use zeno::{Command, Fill, Format, Join, Mask, PathBuilder, Stroke, Style, Vector};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct GlyphKey {
|
||||
@ -262,27 +262,26 @@ pub enum PolyCommand {
|
||||
}
|
||||
|
||||
impl PolyCommand {
|
||||
fn to_zeno(
|
||||
&self,
|
||||
width: usize,
|
||||
height: usize,
|
||||
underline_height: f32,
|
||||
sink: &mut impl PathBuilder,
|
||||
) {
|
||||
let coord = |x: &BlockCoord, y: &BlockCoord| {
|
||||
Vector::new(
|
||||
fn to_skia(&self, width: usize, height: usize, underline_height: f32, pb: &mut PathBuilder) {
|
||||
match self {
|
||||
Self::MoveTo(x, y) => pb.move_to(
|
||||
x.to_pixel(width, underline_height),
|
||||
y.to_pixel(height, underline_height),
|
||||
)
|
||||
};
|
||||
|
||||
let point = |(x, y): &BlockPoint| coord(x, y);
|
||||
|
||||
match self {
|
||||
Self::MoveTo(x, y) => sink.move_to(coord(x, y)),
|
||||
Self::LineTo(x, y) => sink.line_to(coord(x, y)),
|
||||
Self::QuadTo { control, to } => sink.quad_to(point(control), point(to)),
|
||||
Self::Close => sink.close(),
|
||||
),
|
||||
Self::LineTo(x, y) => pb.line_to(
|
||||
x.to_pixel(width, underline_height),
|
||||
y.to_pixel(height, underline_height),
|
||||
),
|
||||
Self::QuadTo {
|
||||
control: (x1, y1),
|
||||
to: (x, y),
|
||||
} => pb.quad_to(
|
||||
x1.to_pixel(width, underline_height),
|
||||
y1.to_pixel(height, underline_height),
|
||||
x.to_pixel(width, underline_height),
|
||||
y.to_pixel(height, underline_height),
|
||||
),
|
||||
Self::Close => pb.close(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -297,11 +296,20 @@ pub enum PolyStyle {
|
||||
}
|
||||
|
||||
impl PolyStyle {
|
||||
fn to_zeno(self, width: f32) -> Style<'static> {
|
||||
fn apply(self, width: f32, paint: &Paint, path: &Path, pixmap: &mut PixmapMut) {
|
||||
match self {
|
||||
Self::Fill => Style::default(),
|
||||
Self::Outline => Style::Stroke(*Stroke::new(width).join(Join::Miter)),
|
||||
Self::OutlineHeavy => Style::Stroke(*Stroke::new(2. * width).join(Join::Miter)),
|
||||
PolyStyle::Fill => {
|
||||
pixmap.fill_path(path, paint, FillRule::Winding, Transform::identity(), None);
|
||||
}
|
||||
|
||||
PolyStyle::Outline | PolyStyle::OutlineHeavy => {
|
||||
let mut stroke = Stroke::default();
|
||||
stroke.width = width;
|
||||
if self == PolyStyle::OutlineHeavy {
|
||||
stroke.width *= 2.0;
|
||||
}
|
||||
pixmap.stroke_path(path, paint, &stroke, Transform::identity(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2611,23 +2619,28 @@ impl<T: Texture2d> GlyphCache<T> {
|
||||
// Fill a rectangular region described by the x and y ranges
|
||||
let fill_rect = |buffer: &mut Image, x: Range<usize>, y: Range<usize>| {
|
||||
let (width, height) = buffer.image_dimensions();
|
||||
let mut pixmap =
|
||||
PixmapMut::from_bytes(buffer.pixel_data_slice_mut(), width as u32, height as u32)
|
||||
.expect("make pixmap from existing bitmap");
|
||||
|
||||
let x = x.start as f32..x.end as f32;
|
||||
let y = y.start as f32..y.end as f32;
|
||||
let mut path: Vec<Command> = vec![];
|
||||
|
||||
path.add_rect([x.start, y.start], x.end - x.start, y.end - y.start);
|
||||
let (alpha, _placement) = Mask::new(&path)
|
||||
.format(Format::Alpha)
|
||||
.size(width as u32, height as u32)
|
||||
.style(Fill::NonZero)
|
||||
.render();
|
||||
let path = PathBuilder::from_rect(
|
||||
tiny_skia::Rect::from_xywh(x.start, y.start, x.end - x.start, y.end - y.start)
|
||||
.expect("valid rect"),
|
||||
);
|
||||
|
||||
for (alpha, dest) in alpha.into_iter().zip(buffer.pixels_mut()) {
|
||||
let alpha = alpha as u32;
|
||||
// If existing pixel was blank, we want to replace it.
|
||||
// If alpha is blank then we don't want to replace existing non-blank.
|
||||
*dest |= alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
}
|
||||
let mut paint = Paint::default();
|
||||
paint.set_color(tiny_skia::Color::WHITE);
|
||||
|
||||
pixmap.fill_path(
|
||||
&path,
|
||||
&paint,
|
||||
FillRule::Winding,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
};
|
||||
|
||||
match block {
|
||||
@ -2716,35 +2729,34 @@ impl<T: Texture2d> GlyphCache<T> {
|
||||
}
|
||||
BlockKey::Poly(polys) => {
|
||||
let (width, height) = buffer.image_dimensions();
|
||||
let mut pixmap = PixmapMut::from_bytes(
|
||||
buffer.pixel_data_slice_mut(),
|
||||
width as u32,
|
||||
height as u32,
|
||||
)
|
||||
.expect("make pixmap from existing bitmap");
|
||||
|
||||
for Poly {
|
||||
path,
|
||||
intensity,
|
||||
style,
|
||||
} in polys
|
||||
{
|
||||
let intensity = intensity.to_scale();
|
||||
let mut cmd = vec![];
|
||||
let intensity = (intensity.to_scale() * 255.) as u8;
|
||||
let mut paint = Paint::default();
|
||||
paint.set_color_rgba8(intensity, intensity, intensity, intensity);
|
||||
paint.anti_alias = false; // explicitly do not want AA for small sizes
|
||||
let mut pb = PathBuilder::new();
|
||||
for item in path.iter() {
|
||||
item.to_zeno(
|
||||
width,
|
||||
height,
|
||||
self.metrics.underline_height as f32,
|
||||
&mut cmd,
|
||||
);
|
||||
}
|
||||
|
||||
let (alpha, _placement) = Mask::new(&cmd)
|
||||
.format(Format::Alpha)
|
||||
.style(style.to_zeno(self.metrics.underline_height as f32))
|
||||
.size(width as u32, height as u32)
|
||||
.render();
|
||||
|
||||
for (alpha, dest) in alpha.into_iter().zip(buffer.pixels_mut()) {
|
||||
let alpha = (intensity * (alpha as f32)) as u32;
|
||||
// If existing pixel was blank, we want to replace it.
|
||||
// If alpha is blank then we don't want to replace existing non-blank.
|
||||
*dest |= alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
item.to_skia(width, height, self.metrics.underline_height as f32, &mut pb);
|
||||
}
|
||||
let path = pb.finish().expect("poly path to be valid");
|
||||
style.apply(
|
||||
self.metrics.underline_height as f32,
|
||||
&paint,
|
||||
&path,
|
||||
&mut pixmap,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,14 @@ pub trait BitmapImage {
|
||||
/// Return the pair (width, height) of the image, measured in pixels
|
||||
fn image_dimensions(&self) -> (usize, usize);
|
||||
|
||||
fn pixel_data_slice_mut(&mut self) -> &mut [u8] {
|
||||
let (width, height) = self.image_dimensions();
|
||||
unsafe {
|
||||
let first = self.pixel_data_mut();
|
||||
std::slice::from_raw_parts_mut(first, width * height * 4)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pixels(&self) -> &[u32] {
|
||||
let (width, height) = self.image_dimensions();
|
||||
|
Loading…
Reference in New Issue
Block a user