font/sprite: update to z2d 0.12.1, use native path insetting (#13489)
This change updates z2d to 0.12.1 and changes the sprite font path insetting functionality to use the new path offset abilities released in the update. In addition, there has been a slight change to the drawing of E0B5 and its respective reflection; we now add a 1-pixel horizontal line segment to each end to force them to be perpendicular. This is because offsetting pre-expands the curves and ultimately causes the end segments of the curve itself to have slight non-horizontal angles, which produce small artifacts at the ends without the forced horizontal ends.
@@ -30,8 +30,8 @@
|
||||
},
|
||||
.z2d = .{
|
||||
// vancluever/z2d
|
||||
.url = "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
.hash = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
.url = "https://github.com/vancluever/z2d/archive/7dbae85c81784dba9988320bf9543ed9a81350c8.tar.gz",
|
||||
.hash = "z2d-0.12.1-j5P_Hsw8EQAKyZTQICCQnAH2xYkLDW8k9uefbsYdfPZ-",
|
||||
.lazy = true,
|
||||
},
|
||||
.zig_objc = .{
|
||||
|
||||
6
build.zig.zon.json
generated
@@ -154,10 +154,10 @@
|
||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
|
||||
},
|
||||
"z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR": {
|
||||
"z2d-0.12.1-j5P_Hsw8EQAKyZTQICCQnAH2xYkLDW8k9uefbsYdfPZ-": {
|
||||
"name": "z2d",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
"hash": "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA="
|
||||
"url": "https://github.com/vancluever/z2d/archive/7dbae85c81784dba9988320bf9543ed9a81350c8.tar.gz",
|
||||
"hash": "sha256-Fjr1ORn0ozxU7QY09o2ZOZQHIJsXfVw0UCdZxTKmZJ0="
|
||||
},
|
||||
"zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW": {
|
||||
"name": "zf",
|
||||
|
||||
6
build.zig.zon.nix
generated
@@ -377,11 +377,11 @@ in
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR";
|
||||
name = "z2d-0.12.1-j5P_Hsw8EQAKyZTQICCQnAH2xYkLDW8k9uefbsYdfPZ-";
|
||||
path = fetchZigArtifact {
|
||||
name = "z2d";
|
||||
url = "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz";
|
||||
hash = "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA=";
|
||||
url = "https://github.com/vancluever/z2d/archive/7dbae85c81784dba9988320bf9543ed9a81350c8.tar.gz";
|
||||
hash = "sha256-Fjr1ORn0ozxU7QY09o2ZOZQHIJsXfVw0UCdZxTKmZJ0=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
|
||||
2
build.zig.zon.txt
generated
@@ -30,9 +30,9 @@ https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaP
|
||||
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
|
||||
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz
|
||||
https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz
|
||||
https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz
|
||||
https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz
|
||||
https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz
|
||||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||
https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz
|
||||
https://github.com/vancluever/z2d/archive/7dbae85c81784dba9988320bf9543ed9a81350c8.tar.gz
|
||||
|
||||
@@ -187,9 +187,9 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
"dest": "vendor/p/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
"sha256": "d48b117307f767ca379bf31bd171880e66dcafb89eca4a8f923222619992fcb4"
|
||||
"url": "https://github.com/vancluever/z2d/archive/7dbae85c81784dba9988320bf9543ed9a81350c8.tar.gz",
|
||||
"dest": "vendor/p/z2d-0.12.1-j5P_Hsw8EQAKyZTQICCQnAH2xYkLDW8k9uefbsYdfPZ-",
|
||||
"sha256": "e55c9d0b156edaddfea32fb1c0e3597e1b6306b9a4ec1888e2f8008c598bced8"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
|
||||
@@ -375,85 +375,17 @@ pub const Canvas = struct {
|
||||
);
|
||||
}
|
||||
|
||||
/// Do an inner stroke on a z2d path, right now this involves a pretty
|
||||
/// heavy workaround that uses two extra surfaces; in the future, z2d
|
||||
/// should add inner and outer strokes natively.
|
||||
/// Do an inner stroke using a 1/2 stroke width inset of the supplied
|
||||
/// `path`.
|
||||
pub fn innerStrokePath(
|
||||
self: *Canvas,
|
||||
path: z2d.Path,
|
||||
opts: z2d.painter.StrokeOptions,
|
||||
color: Color,
|
||||
) (z2d.painter.StrokeError || z2d.painter.FillError)!void {
|
||||
// On one surface we fill the shape, this will be a mask we
|
||||
// multiply with the double-width stroke so that only the
|
||||
// part inside is used.
|
||||
var fill_sfc: z2d.Surface = try .init(
|
||||
.image_surface_alpha8,
|
||||
self.alloc,
|
||||
self.sfc.getWidth(),
|
||||
self.sfc.getHeight(),
|
||||
);
|
||||
defer fill_sfc.deinit(self.alloc);
|
||||
|
||||
// On the other we'll do the double width stroke.
|
||||
var stroke_sfc: z2d.Surface = try .init(
|
||||
.image_surface_alpha8,
|
||||
self.alloc,
|
||||
self.sfc.getWidth(),
|
||||
self.sfc.getHeight(),
|
||||
);
|
||||
defer stroke_sfc.deinit(self.alloc);
|
||||
|
||||
// Make a closed version of the path for our fill, so
|
||||
// that we can support open paths for inner stroke.
|
||||
var closed_path = path;
|
||||
closed_path.nodes = try path.nodes.clone(self.alloc);
|
||||
defer closed_path.deinit(self.alloc);
|
||||
try closed_path.close(self.alloc);
|
||||
|
||||
// Fill the shape in white to the fill surface, we use
|
||||
// white because this is a mask that we'll multiply with
|
||||
// the stroke, we want everything inside to be the stroke
|
||||
// color.
|
||||
try z2d.painter.fill(
|
||||
self.alloc,
|
||||
&fill_sfc,
|
||||
&.{ .opaque_pattern = .{
|
||||
.pixel = .{ .alpha8 = .{ .a = 255 } },
|
||||
} },
|
||||
closed_path.nodes.items,
|
||||
.{},
|
||||
);
|
||||
|
||||
// Stroke the shape with double the desired width.
|
||||
var mut_opts = opts;
|
||||
mut_opts.line_width *= 2;
|
||||
try z2d.painter.stroke(
|
||||
self.alloc,
|
||||
&stroke_sfc,
|
||||
&.{ .opaque_pattern = .{
|
||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } },
|
||||
} },
|
||||
path.nodes.items,
|
||||
mut_opts,
|
||||
);
|
||||
|
||||
// We multiply the stroke sfc on to the fill surface.
|
||||
// The z2d composite operation doesn't seem to work for
|
||||
// this with alpha8 surfaces, so we have to do it manually.
|
||||
for (
|
||||
std.mem.sliceAsBytes(fill_sfc.image_surface_alpha8.buf),
|
||||
std.mem.sliceAsBytes(stroke_sfc.image_surface_alpha8.buf),
|
||||
) |*d, s| {
|
||||
d.* = @intFromFloat(@round(
|
||||
255.0 *
|
||||
(@as(f64, @floatFromInt(s)) / 255.0) *
|
||||
(@as(f64, @floatFromInt(d.*)) / 255.0),
|
||||
));
|
||||
}
|
||||
|
||||
// Then we composite the result on to the main surface.
|
||||
self.sfc.composite(&fill_sfc, .src_over, 0, 0, .{});
|
||||
) (z2d.Path.OffsetError || z2d.painter.StrokeError)!void {
|
||||
var inset_path = try path.offset(self.alloc, -opts.line_width / 2.0);
|
||||
defer inset_path.deinit(self.alloc);
|
||||
return self.strokePath(inset_path, opts, color);
|
||||
}
|
||||
|
||||
/// Fill a z2d path.
|
||||
|
||||
@@ -292,8 +292,13 @@ pub fn drawE0B5(
|
||||
|
||||
const radius: f64 = @min(float_width, float_height / 2);
|
||||
|
||||
var path = canvas.staticPath(4);
|
||||
// Note on the first/final lineTo moves: this is to enforce horizontal
|
||||
// lines on both ends. This ensures that when the path is offset and
|
||||
// stroked, the ends are butt-capped entirely perpendicularly; curveTo
|
||||
// lerping would produce very slight slopes otherwise.
|
||||
var path = canvas.staticPath(6);
|
||||
path.moveTo(0, 0);
|
||||
path.lineTo(1, 0);
|
||||
path.curveTo(
|
||||
radius * c,
|
||||
0,
|
||||
@@ -308,9 +313,10 @@ pub fn drawE0B5(
|
||||
float_height - radius + radius * c,
|
||||
radius * c,
|
||||
float_height,
|
||||
0,
|
||||
1,
|
||||
float_height,
|
||||
);
|
||||
path.lineTo(0, float_height);
|
||||
|
||||
try canvas.innerStrokePath(path.wrapped_path, .{
|
||||
.line_width = @floatFromInt(metrics.box_thickness),
|
||||
|
||||
BIN
src/font/sprite/testdata/U+2500...U+25FF-11x21+2.png
vendored
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
src/font/sprite/testdata/U+2500...U+25FF-9x17+1.png
vendored
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
src/font/sprite/testdata/U+E000...U+E0FF-11x21+2.png
vendored
|
Before Width: | Height: | Size: 1009 B After Width: | Height: | Size: 1.0 KiB |
BIN
src/font/sprite/testdata/U+E000...U+E0FF-12x24+3.png
vendored
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
src/font/sprite/testdata/U+E000...U+E0FF-18x36+4.png
vendored
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
src/font/sprite/testdata/U+E000...U+E0FF-9x17+1.png
vendored
|
Before Width: | Height: | Size: 832 B After Width: | Height: | Size: 834 B |