mirror of
https://github.com/wez/wezterm.git
synced 2024-11-23 15:04:36 +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",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -3654,6 +3660,15 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
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]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
@ -4301,6 +4316,20 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"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]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -4915,6 +4944,7 @@ dependencies = [
|
|||||||
"termwiz",
|
"termwiz",
|
||||||
"textwrap 0.14.0",
|
"textwrap 0.14.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tiny-skia",
|
||||||
"umask",
|
"umask",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
@ -4931,7 +4961,6 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
"window",
|
"window",
|
||||||
"windows",
|
"windows",
|
||||||
"zeno",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5421,12 +5450,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zeno"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea708573d4a67f939793b0d3f923d105bfdf06bbd6acb3f9cd02ce1bd905f6c8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zstd"
|
name = "zstd"
|
||||||
version = "0.6.1+zstd.1.4.9"
|
version = "0.6.1+zstd.1.4.9"
|
||||||
|
@ -57,6 +57,7 @@ terminfo = "0.7"
|
|||||||
termwiz = { path = "../termwiz" }
|
termwiz = { path = "../termwiz" }
|
||||||
textwrap = "0.14"
|
textwrap = "0.14"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
tiny-skia = "0.5"
|
||||||
umask = { path = "../umask" }
|
umask = { path = "../umask" }
|
||||||
unicode-normalization = "0.1"
|
unicode-normalization = "0.1"
|
||||||
unicode-segmentation = "1.7"
|
unicode-segmentation = "1.7"
|
||||||
@ -71,7 +72,6 @@ wezterm-ssh = { path = "../wezterm-ssh" }
|
|||||||
wezterm-term = { path = "../term", features=["use_serde"] }
|
wezterm-term = { path = "../term", features=["use_serde"] }
|
||||||
wezterm-toast-notification = { path = "../wezterm-toast-notification" }
|
wezterm-toast-notification = { path = "../wezterm-toast-notification" }
|
||||||
window = { path = "../window" }
|
window = { path = "../window" }
|
||||||
zeno = "0.2"
|
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies]
|
[target."cfg(windows)".dependencies]
|
||||||
shared_library = "0.1"
|
shared_library = "0.1"
|
||||||
|
@ -18,10 +18,10 @@ use std::rc::Rc;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use termwiz::image::ImageData;
|
use termwiz::image::ImageData;
|
||||||
|
use tiny_skia::{FillRule, Paint, Path, PathBuilder, PixmapMut, Stroke, Transform};
|
||||||
use wezterm_font::units::*;
|
use wezterm_font::units::*;
|
||||||
use wezterm_font::{FontConfiguration, GlyphInfo};
|
use wezterm_font::{FontConfiguration, GlyphInfo};
|
||||||
use wezterm_term::Underline;
|
use wezterm_term::Underline;
|
||||||
use zeno::{Command, Fill, Format, Join, Mask, PathBuilder, Stroke, Style, Vector};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct GlyphKey {
|
pub struct GlyphKey {
|
||||||
@ -262,27 +262,26 @@ pub enum PolyCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PolyCommand {
|
impl PolyCommand {
|
||||||
fn to_zeno(
|
fn to_skia(&self, width: usize, height: usize, underline_height: f32, pb: &mut PathBuilder) {
|
||||||
&self,
|
match self {
|
||||||
width: usize,
|
Self::MoveTo(x, y) => pb.move_to(
|
||||||
height: usize,
|
|
||||||
underline_height: f32,
|
|
||||||
sink: &mut impl PathBuilder,
|
|
||||||
) {
|
|
||||||
let coord = |x: &BlockCoord, y: &BlockCoord| {
|
|
||||||
Vector::new(
|
|
||||||
x.to_pixel(width, underline_height),
|
x.to_pixel(width, underline_height),
|
||||||
y.to_pixel(height, underline_height),
|
y.to_pixel(height, underline_height),
|
||||||
)
|
),
|
||||||
};
|
Self::LineTo(x, y) => pb.line_to(
|
||||||
|
x.to_pixel(width, underline_height),
|
||||||
let point = |(x, y): &BlockPoint| coord(x, y);
|
y.to_pixel(height, underline_height),
|
||||||
|
),
|
||||||
match self {
|
Self::QuadTo {
|
||||||
Self::MoveTo(x, y) => sink.move_to(coord(x, y)),
|
control: (x1, y1),
|
||||||
Self::LineTo(x, y) => sink.line_to(coord(x, y)),
|
to: (x, y),
|
||||||
Self::QuadTo { control, to } => sink.quad_to(point(control), point(to)),
|
} => pb.quad_to(
|
||||||
Self::Close => sink.close(),
|
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 {
|
impl PolyStyle {
|
||||||
fn to_zeno(self, width: f32) -> Style<'static> {
|
fn apply(self, width: f32, paint: &Paint, path: &Path, pixmap: &mut PixmapMut) {
|
||||||
match self {
|
match self {
|
||||||
Self::Fill => Style::default(),
|
PolyStyle::Fill => {
|
||||||
Self::Outline => Style::Stroke(*Stroke::new(width).join(Join::Miter)),
|
pixmap.fill_path(path, paint, FillRule::Winding, Transform::identity(), None);
|
||||||
Self::OutlineHeavy => Style::Stroke(*Stroke::new(2. * width).join(Join::Miter)),
|
}
|
||||||
|
|
||||||
|
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
|
// Fill a rectangular region described by the x and y ranges
|
||||||
let fill_rect = |buffer: &mut Image, x: Range<usize>, y: Range<usize>| {
|
let fill_rect = |buffer: &mut Image, x: Range<usize>, y: Range<usize>| {
|
||||||
let (width, height) = buffer.image_dimensions();
|
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 x = x.start as f32..x.end as f32;
|
||||||
let y = y.start as f32..y.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 path = PathBuilder::from_rect(
|
||||||
let (alpha, _placement) = Mask::new(&path)
|
tiny_skia::Rect::from_xywh(x.start, y.start, x.end - x.start, y.end - y.start)
|
||||||
.format(Format::Alpha)
|
.expect("valid rect"),
|
||||||
.size(width as u32, height as u32)
|
);
|
||||||
.style(Fill::NonZero)
|
|
||||||
.render();
|
|
||||||
|
|
||||||
for (alpha, dest) in alpha.into_iter().zip(buffer.pixels_mut()) {
|
let mut paint = Paint::default();
|
||||||
let alpha = alpha as u32;
|
paint.set_color(tiny_skia::Color::WHITE);
|
||||||
// If existing pixel was blank, we want to replace it.
|
|
||||||
// If alpha is blank then we don't want to replace existing non-blank.
|
pixmap.fill_path(
|
||||||
*dest |= alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
&path,
|
||||||
}
|
&paint,
|
||||||
|
FillRule::Winding,
|
||||||
|
Transform::identity(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
match block {
|
match block {
|
||||||
@ -2716,35 +2729,34 @@ impl<T: Texture2d> GlyphCache<T> {
|
|||||||
}
|
}
|
||||||
BlockKey::Poly(polys) => {
|
BlockKey::Poly(polys) => {
|
||||||
let (width, height) = buffer.image_dimensions();
|
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 {
|
for Poly {
|
||||||
path,
|
path,
|
||||||
intensity,
|
intensity,
|
||||||
style,
|
style,
|
||||||
} in polys
|
} in polys
|
||||||
{
|
{
|
||||||
let intensity = intensity.to_scale();
|
let intensity = (intensity.to_scale() * 255.) as u8;
|
||||||
let mut cmd = vec![];
|
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() {
|
for item in path.iter() {
|
||||||
item.to_zeno(
|
item.to_skia(width, height, self.metrics.underline_height as f32, &mut pb);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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
|
/// Return the pair (width, height) of the image, measured in pixels
|
||||||
fn image_dimensions(&self) -> (usize, usize);
|
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]
|
#[inline]
|
||||||
fn pixels(&self) -> &[u32] {
|
fn pixels(&self) -> &[u32] {
|
||||||
let (width, height) = self.image_dimensions();
|
let (width, height) = self.image_dimensions();
|
||||||
|
Loading…
Reference in New Issue
Block a user