mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
kind of handle VS15/16 better, its not blank anymore, but its wrong
This commit is contained in:
@ -158,7 +158,7 @@ pub fn indexForCodepoint(
|
|||||||
if (gop.found_existing) return gop.value_ptr.*;
|
if (gop.found_existing) return gop.value_ptr.*;
|
||||||
|
|
||||||
// Load a value and cache it. This even caches negative matches.
|
// Load a value and cache it. This even caches negative matches.
|
||||||
const value = self.group.indexForCodepoint(cp, style, null);
|
const value = self.group.indexForCodepoint(cp, style, p);
|
||||||
gop.value_ptr.* = value;
|
gop.value_ptr.* = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ const Group = @import("main.zig").Group;
|
|||||||
const GroupCache = @import("main.zig").GroupCache;
|
const GroupCache = @import("main.zig").GroupCache;
|
||||||
const Library = @import("main.zig").Library;
|
const Library = @import("main.zig").Library;
|
||||||
const Style = @import("main.zig").Style;
|
const Style = @import("main.zig").Style;
|
||||||
|
const Presentation = @import("main.zig").Presentation;
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.font_shaper);
|
const log = std.log.scoped(.font_shaper);
|
||||||
@ -85,12 +86,12 @@ pub fn shape(self: *Shaper, run: TextRun) ![]Cell {
|
|||||||
// we're the last cell, this is remaining otherwise we use cluster numbers
|
// we're the last cell, this is remaining otherwise we use cluster numbers
|
||||||
// to detect since we set the cluster number to the column it
|
// to detect since we set the cluster number to the column it
|
||||||
// originated.
|
// originated.
|
||||||
const cp_width = if (i == info.len - 1)
|
const cp_width = @maximum(1, if (i == info.len - 1)
|
||||||
(run.max_cluster - v.cluster) + 1 // + 1 because we're zero indexed
|
(run.max_cluster - v.cluster) + 1 // + 1 because we're zero indexed
|
||||||
else width: {
|
else width: {
|
||||||
const next_cluster = info[i + 1].cluster;
|
const next_cluster = info[i + 1].cluster;
|
||||||
break :width next_cluster - v.cluster;
|
break :width next_cluster - v.cluster;
|
||||||
};
|
});
|
||||||
|
|
||||||
self.cell_buf[i] = .{
|
self.cell_buf[i] = .{
|
||||||
.x = x,
|
.x = x,
|
||||||
@ -174,6 +175,17 @@ pub const RunIterator = struct {
|
|||||||
else
|
else
|
||||||
.regular;
|
.regular;
|
||||||
|
|
||||||
|
// Determine the presentation format for this glyph.
|
||||||
|
const presentation: ?Presentation = if (cell.attrs.grapheme) p: {
|
||||||
|
var it = self.row.codepointIterator(j);
|
||||||
|
while (it.next()) |cp| {
|
||||||
|
if (cp == 0xFE0E) break :p Presentation.text;
|
||||||
|
if (cp == 0xFE0F) break :p Presentation.emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :p null;
|
||||||
|
} else null;
|
||||||
|
|
||||||
// Determine the font for this cell. We'll use fallbacks
|
// Determine the font for this cell. We'll use fallbacks
|
||||||
// manually here to try replacement chars and then a space
|
// manually here to try replacement chars and then a space
|
||||||
// for unknown glyphs.
|
// for unknown glyphs.
|
||||||
@ -181,14 +193,14 @@ pub const RunIterator = struct {
|
|||||||
alloc,
|
alloc,
|
||||||
cell.char,
|
cell.char,
|
||||||
style,
|
style,
|
||||||
null,
|
presentation,
|
||||||
)) orelse (try self.shaper.group.indexForCodepoint(
|
)) orelse (try self.shaper.group.indexForCodepoint(
|
||||||
alloc,
|
alloc,
|
||||||
0xFFFD,
|
0xFFFD,
|
||||||
style,
|
style,
|
||||||
null,
|
.text,
|
||||||
)) orelse
|
)) orelse
|
||||||
try self.shaper.group.indexForCodepoint(alloc, ' ', style, null);
|
try self.shaper.group.indexForCodepoint(alloc, ' ', style, .text);
|
||||||
const font_idx = font_idx_opt.?;
|
const font_idx = font_idx_opt.?;
|
||||||
//log.warn("char={x} idx={}", .{ cell.char, font_idx });
|
//log.warn("char={x} idx={}", .{ cell.char, font_idx });
|
||||||
if (j == self.i) current_font = font_idx;
|
if (j == self.i) current_font = font_idx;
|
||||||
@ -380,39 +392,73 @@ test "shape emoji width" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test "shape variation selector VS15" {
|
test "shape variation selector VS15" {
|
||||||
// const testing = std.testing;
|
const testing = std.testing;
|
||||||
// const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
//
|
|
||||||
// var testdata = try testShaper(alloc);
|
var testdata = try testShaper(alloc);
|
||||||
// defer testdata.deinit();
|
defer testdata.deinit();
|
||||||
//
|
|
||||||
// var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
// var buf_idx: usize = 0;
|
var buf_idx: usize = 0;
|
||||||
// buf_idx += try std.unicode.utf8Encode(0x263A, buf[buf_idx..]); // White smiling face (text)
|
buf_idx += try std.unicode.utf8Encode(0x270C, buf[buf_idx..]); // Victory sign (default text)
|
||||||
// buf_idx += try std.unicode.utf8Encode(0xFE0F, buf[buf_idx..]); // ZWJ to force color
|
buf_idx += try std.unicode.utf8Encode(0xFE0E, buf[buf_idx..]); // ZWJ to force text
|
||||||
//
|
|
||||||
// // Make a screen with some data
|
// Make a screen with some data
|
||||||
// var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
||||||
// defer screen.deinit();
|
defer screen.deinit();
|
||||||
// try screen.testWriteString(buf[0..buf_idx]);
|
try screen.testWriteString(buf[0..buf_idx]);
|
||||||
//
|
|
||||||
// // Get our run iterator
|
// Get our run iterator
|
||||||
// var shaper = testdata.shaper;
|
var shaper = testdata.shaper;
|
||||||
// var it = shaper.runIterator(screen.getRow(.{ .screen = 0 }));
|
var it = shaper.runIterator(screen.getRow(.{ .screen = 0 }));
|
||||||
// var count: usize = 0;
|
var count: usize = 0;
|
||||||
// while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
// count += 1;
|
count += 1;
|
||||||
// //try testing.expectEqual(@as(u32, 2), shaper.hb_buf.getLength());
|
try testing.expectEqual(@as(u32, 2), shaper.hb_buf.getLength());
|
||||||
//
|
|
||||||
// const cells = try shaper.shape(run);
|
const cells = try shaper.shape(run);
|
||||||
// try testing.expectEqual(@as(usize, 2), cells.len);
|
try testing.expectEqual(@as(usize, 2), cells.len);
|
||||||
// log.warn("WHAT={}", .{cells[0]});
|
try testing.expectEqual(@as(u8, 1), cells[0].width);
|
||||||
// log.warn("WHAT={}", .{cells[1]});
|
try testing.expectEqual(@as(u8, 1), cells[1].width);
|
||||||
// try testing.expectEqual(@as(u8, 2), cells[0].width);
|
}
|
||||||
// }
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
// try testing.expectEqual(@as(usize, 1), count);
|
}
|
||||||
// }
|
|
||||||
|
test "shape variation selector VS16" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var testdata = try testShaper(alloc);
|
||||||
|
defer testdata.deinit();
|
||||||
|
|
||||||
|
var buf: [32]u8 = undefined;
|
||||||
|
var buf_idx: usize = 0;
|
||||||
|
buf_idx += try std.unicode.utf8Encode(0x270C, buf[buf_idx..]); // Victory sign (default text)
|
||||||
|
buf_idx += try std.unicode.utf8Encode(0xFE0F, buf[buf_idx..]); // ZWJ to force color
|
||||||
|
|
||||||
|
// Make a screen with some data
|
||||||
|
var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
||||||
|
defer screen.deinit();
|
||||||
|
try screen.testWriteString(buf[0..buf_idx]);
|
||||||
|
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = testdata.shaper;
|
||||||
|
var it = shaper.runIterator(screen.getRow(.{ .screen = 0 }));
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
try testing.expectEqual(@as(u32, 2), shaper.hb_buf.getLength());
|
||||||
|
|
||||||
|
const cells = try shaper.shape(run);
|
||||||
|
try testing.expectEqual(@as(usize, 1), cells.len);
|
||||||
|
|
||||||
|
// TODO: this should pass, victory sign is width one but
|
||||||
|
// after forcing color it is width 2
|
||||||
|
//try testing.expectEqual(@as(u8, 2), cells[0].width);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
}
|
||||||
|
|
||||||
const TestShaper = struct {
|
const TestShaper = struct {
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
@ -434,6 +480,7 @@ const TestShaper = struct {
|
|||||||
fn testShaper(alloc: Allocator) !TestShaper {
|
fn testShaper(alloc: Allocator) !TestShaper {
|
||||||
const testFont = @import("test.zig").fontRegular;
|
const testFont = @import("test.zig").fontRegular;
|
||||||
const testEmoji = @import("test.zig").fontEmoji;
|
const testEmoji = @import("test.zig").fontEmoji;
|
||||||
|
const testEmojiText = @import("test.zig").fontEmojiText;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init();
|
||||||
errdefer lib.deinit();
|
errdefer lib.deinit();
|
||||||
@ -446,6 +493,7 @@ fn testShaper(alloc: Allocator) !TestShaper {
|
|||||||
// Setup group
|
// Setup group
|
||||||
try cache_ptr.group.addFace(alloc, .regular, try Face.init(lib, testFont, .{ .points = 12 }));
|
try cache_ptr.group.addFace(alloc, .regular, try Face.init(lib, testFont, .{ .points = 12 }));
|
||||||
try cache_ptr.group.addFace(alloc, .regular, try Face.init(lib, testEmoji, .{ .points = 12 }));
|
try cache_ptr.group.addFace(alloc, .regular, try Face.init(lib, testEmoji, .{ .points = 12 }));
|
||||||
|
try cache_ptr.group.addFace(alloc, .regular, try Face.init(lib, testEmojiText, .{ .points = 12 }));
|
||||||
|
|
||||||
var cell_buf = try alloc.alloc(Cell, 80);
|
var cell_buf = try alloc.alloc(Cell, 80);
|
||||||
errdefer alloc.free(cell_buf);
|
errdefer alloc.free(cell_buf);
|
||||||
|
Reference in New Issue
Block a user