mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-28 12:21:55 +00:00
Implement underline exclusion
This commit is contained in:
parent
eb322913c3
commit
1707e603f3
6 changed files with 52 additions and 15 deletions
|
|
@ -15,6 +15,7 @@ in vec3 sprite_pos;
|
|||
in vec3 underline_pos;
|
||||
in vec3 cursor_pos;
|
||||
in vec3 strike_pos;
|
||||
in vec3 underline_exclusion_pos;
|
||||
in vec3 foreground;
|
||||
in vec4 cursor_color_premult;
|
||||
in vec3 decoration_fg;
|
||||
|
|
@ -128,6 +129,8 @@ vec4 load_text_foreground_color() {
|
|||
vec4 calculate_premul_foreground_from_sprites(vec4 text_fg) {
|
||||
// Return premul foreground color from decorations (cursor, underline, strikethrough)
|
||||
float underline_alpha = texture(sprites, underline_pos).a;
|
||||
float underline_exclusion = texture(sprites, underline_exclusion_pos).a;
|
||||
underline_alpha *= 1.0f - underline_exclusion;
|
||||
float strike_alpha = texture(sprites, strike_pos).a;
|
||||
float cursor_alpha = texture(sprites, cursor_pos).a;
|
||||
// Since strike and text are the same color, we simply add the alpha values
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ layout(std140) uniform CellRenderData {
|
|||
|
||||
uint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
|
||||
uint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx;
|
||||
uint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx, cell_height;
|
||||
float cursor_x, cursor_y, cursor_w, cursor_opacity;
|
||||
|
||||
// must have unique entries with 0 being default_bg and unset being UINT32_MAX
|
||||
|
|
@ -51,6 +51,7 @@ out vec3 underline_pos;
|
|||
out vec3 cursor_pos;
|
||||
out vec4 cursor_color_premult;
|
||||
out vec3 strike_pos;
|
||||
out vec3 underline_exclusion_pos;
|
||||
out vec3 foreground;
|
||||
out vec3 decoration_fg;
|
||||
out float colored_sprite;
|
||||
|
|
@ -108,9 +109,18 @@ vec3 to_sprite_pos(uvec2 pos, uint idx) {
|
|||
uvec3 c = to_sprite_coords(idx);
|
||||
vec2 s_xpos = vec2(c.x, float(c.x) + 1.0f) * (1.0f / float(sprites_xnum));
|
||||
vec2 s_ypos = vec2(c.y, float(c.y) + 1.0f) * (1.0f / float(sprites_ynum));
|
||||
uint texture_height_px = (cell_height + 1u) * sprites_ynum;
|
||||
float row_height = 1.0f / float(texture_height_px);
|
||||
s_ypos[1] -= row_height; // skip the decorations_exclude row
|
||||
return vec3(s_xpos[pos.x], s_ypos[pos.y], c.z);
|
||||
}
|
||||
|
||||
vec3 to_underline_exclusion_pos(uvec2 pos, vec3 sprite_pos) {
|
||||
uvec3 c = to_sprite_coords(sprite_idx[0]);
|
||||
float y = (float(c.y) + 1.0f) * (1.0f / float(sprites_ynum));
|
||||
return vec3(sprite_pos.x, y, sprite_pos.z);
|
||||
}
|
||||
|
||||
uint read_sprite_decorations_idx() {
|
||||
int idx = int(sprite_idx[0] & SPRITE_INDEX_MASK);
|
||||
ivec2 sz = textureSize(sprite_decorations_map, 0);
|
||||
|
|
@ -232,6 +242,7 @@ void main() {
|
|||
uvec2 decs = get_decorations_indices(uint(in_url), text_attrs);
|
||||
strike_pos = to_sprite_pos(cell_data.pos, decs[0]);
|
||||
underline_pos = to_sprite_pos(cell_data.pos, decs[1]);
|
||||
underline_exclusion_pos = to_underline_exclusion_pos(cell_data.pos, sprite_pos);
|
||||
|
||||
// Cursor
|
||||
cursor_color_premult = vec4(color_to_vec(cursor_bg) * cursor_opacity, cursor_opacity);
|
||||
|
|
|
|||
|
|
@ -121,12 +121,13 @@ add_dashed_underline(uint8_t *buf, FontCellMetrics fcm) {
|
|||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
static unsigned
|
||||
add_intensity(uint8_t *buf, unsigned x, unsigned y, uint8_t val, unsigned max_y, unsigned position, unsigned cell_width) {
|
||||
y += position;
|
||||
y = MIN(y, max_y);
|
||||
unsigned idx = cell_width * y + x;
|
||||
buf[idx] = MIN(255, buf[idx] + val);
|
||||
return y;
|
||||
}
|
||||
|
||||
DecorationGeometry
|
||||
|
|
@ -152,10 +153,12 @@ add_curl_underline(uint8_t *buf, FontCellMetrics fcm) {
|
|||
for (unsigned x = 0; x < fcm.cell_width; x++) {
|
||||
double y = half_height * cos(x * xfactor);
|
||||
unsigned y1 = (unsigned)floor(y - thickness), y2 = (unsigned)ceil(y);
|
||||
unsigned i1 = (unsigned)(255. * fabs(y - floor(y)));
|
||||
miny = MIN(miny, y1); maxy = MAX(maxy, y2);
|
||||
add_intensity(buf, x, y1, 255 - i1, max_y, position, fcm.cell_width); // upper bound
|
||||
add_intensity(buf, x, y2, i1, max_y, position, fcm.cell_width); // lower bound
|
||||
unsigned intensity = (unsigned)(255. * fabs(y - floor(y)));
|
||||
unsigned i1 = 255 - intensity, i2 = intensity;
|
||||
unsigned yc = add_intensity(buf, x, y1, i1, max_y, position, fcm.cell_width); // upper bound
|
||||
if (i1) { if (yc < miny) miny = yc; if (yc > maxy) maxy = yc; }
|
||||
yc = add_intensity(buf, x, y2, i2, max_y, position, fcm.cell_width); // lower bound
|
||||
if (i2) { if (yc < miny) miny = yc; if (yc > maxy) maxy = yc; }
|
||||
// fill between upper and lower bound
|
||||
for (unsigned t = 1; t <= thickness; t++) add_intensity(buf, x, y1 + t, 255, max_y, position, fcm.cell_width);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ python_send_to_gpu(FontGroup *fg, sprite_index idx, pixel *buf) {
|
|||
|
||||
static void
|
||||
ensure_canvas_can_fit(FontGroup *fg, unsigned cells, unsigned scale) {
|
||||
#define cs(cells, scale) (sizeof(fg->canvas.buf[0]) * 3u * cells * fg->fcm.cell_width * fg->fcm.cell_height * scale * scale)
|
||||
#define cs(cells, scale) (sizeof(fg->canvas.buf[0]) * 3u * cells * fg->fcm.cell_width * (fg->fcm.cell_height + 1) * scale * scale)
|
||||
size_t size_in_bytes = cs(cells, scale);
|
||||
if (size_in_bytes > fg->canvas.size_in_bytes) {
|
||||
free(fg->canvas.buf);
|
||||
|
|
@ -335,11 +335,28 @@ sprite_tracker_set_layout(GPUSpriteTracker *sprite_tracker, unsigned int cell_wi
|
|||
sprite_tracker->x = 0; sprite_tracker->y = 0; sprite_tracker->z = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
calculate_underline_exclusion_zones(pixel *buf, const FontGroup *fg, DecorationGeometry dg) {
|
||||
pixel *ans = buf + fg->fcm.cell_height * fg->fcm.cell_width;
|
||||
const unsigned bottom = MIN(dg.top + dg.height, fg->fcm.cell_height);
|
||||
const unsigned thickness = MAX(1u, fg->fcm.underline_thickness / 1);
|
||||
for (unsigned x = 0; x < fg->fcm.cell_width; x++) {
|
||||
for (unsigned y = dg.top + 2; y < bottom && !ans[x]; y++) {
|
||||
if ((buf[y * fg->fcm.cell_width + x] & 0x000000ff) > 0) {
|
||||
unsigned start_x = x > thickness ? x - thickness : 0;
|
||||
for (unsigned dx = start_x; dx < MIN(x + thickness, fg->fcm.cell_width); dx++) ans[dx] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static sprite_index
|
||||
current_send_sprite_to_gpu(FontGroup *fg, pixel *buf, DecorationMetadata dec) {
|
||||
sprite_index ans = current_sprite_index(&fg->sprite_tracker);
|
||||
if (!do_increment(fg)) return 0;
|
||||
if (python_send_to_gpu_impl) { python_send_to_gpu(fg, ans, buf); return ans; }
|
||||
if (dec.underline_region.height) calculate_underline_exclusion_zones(buf, fg, dec.underline_region);
|
||||
send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, ans, buf, dec.start_idx);
|
||||
if (0) { printf("Sprite: %u dec_idx: %u\n", ans, dec.start_idx); display_rgba_data(buf, fg->fcm.cell_width, fg->fcm.cell_height); printf("\n"); }
|
||||
return ans;
|
||||
|
|
@ -832,7 +849,7 @@ apply_scale_to_font_group(FontGroup *fg, RunFont *rf) {
|
|||
|
||||
static pixel*
|
||||
pointer_to_space_for_last_sprite(Canvas *canvas, FontCellMetrics fcm) {
|
||||
return canvas->buf + (canvas->size_in_bytes / sizeof(canvas->buf[0]) - fcm.cell_width * fcm.cell_height);
|
||||
return canvas->buf + (canvas->size_in_bytes / sizeof(canvas->buf[0]) - fcm.cell_width * (fcm.cell_height + 1));
|
||||
}
|
||||
|
||||
static pixel*
|
||||
|
|
@ -896,12 +913,14 @@ map_scaled_decoration_geometry(DecorationGeometry sdg, Region src, Region dest)
|
|||
unsigned unscaled_top = dest.top + (scaled_top - src.top);
|
||||
unsigned unscaled_bottom = unscaled_top + (scaled_bottom > scaled_top ? scaled_bottom - scaled_top : 0);
|
||||
unscaled_bottom = MIN(unscaled_bottom, dest.bottom);
|
||||
/*printf("111111 src: (%u, %u) dest: (%u, %u) sdg: (%u, %u) scaled: (%u, %u) unscaled: (%u, %u)\n",*/
|
||||
/* src.top, src.bottom, dest.top, dest.bottom, sdg.top, sdg.top + sdg.height, scaled_top, scaled_bottom, unscaled_top, unscaled_bottom);*/
|
||||
return (Region){.top=unscaled_top, .bottom=MAX(unscaled_top, unscaled_bottom)};
|
||||
}
|
||||
|
||||
static void
|
||||
render_scaled_decoration(FontCellMetrics unscaled_metrics, FontCellMetrics scaled_metrics, uint8_t *alpha_mask, pixel *output, Region src, Region dest) {
|
||||
memset(output, 0, unscaled_metrics.cell_width * unscaled_metrics.cell_height * sizeof(output[0]));
|
||||
memset(output, 0, unscaled_metrics.cell_width * (unscaled_metrics.cell_height + 1) * sizeof(output[0]));
|
||||
unsigned src_limit = MIN(scaled_metrics.cell_height, src.bottom), dest_limit = MIN(unscaled_metrics.cell_height, dest.bottom);
|
||||
unsigned cell_width = MIN(scaled_metrics.cell_width, unscaled_metrics.cell_width);
|
||||
for (unsigned srcy = src.top, desty=dest.top; srcy < src_limit && desty < dest_limit; srcy++, desty++) {
|
||||
|
|
@ -918,7 +937,7 @@ render_decorations(FontGroup *fg, Region src, Region dest, FontCellMetrics scale
|
|||
const FontCellMetrics unscaled_metrics = fg->fcm;
|
||||
scaled_metrics.cell_width = unscaled_metrics.cell_width;
|
||||
RAII_ALLOC(uint8_t, alpha_mask, malloc(scaled_metrics.cell_height * scaled_metrics.cell_width));
|
||||
RAII_ALLOC(pixel, buf, malloc(unscaled_metrics.cell_width * unscaled_metrics.cell_height * sizeof(pixel)));
|
||||
RAII_ALLOC(pixel, buf, malloc(unscaled_metrics.cell_width * (unscaled_metrics.cell_height + 1) * sizeof(pixel)));
|
||||
if (!alpha_mask || !buf) fatal("Out of memory");
|
||||
sprite_index ans = 0;
|
||||
bool is_underline = false; uint32_t underline_top = unscaled_metrics.cell_height, underline_bottom = 0;
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ realloc_sprite_texture(FONTS_DATA_HANDLE fg) {
|
|||
sprite_tracker_current_layout(fg, &xnum, &ynum, &z);
|
||||
znum = z + 1;
|
||||
SpriteMap *sprite_map = (SpriteMap*)fg->sprite_map;
|
||||
width = xnum * fg->fcm.cell_width; height = ynum * fg->fcm.cell_height;
|
||||
width = xnum * fg->fcm.cell_width; height = ynum * (fg->fcm.cell_height + 1);
|
||||
const GLenum texture_type = GL_TEXTURE_2D_ARRAY;
|
||||
GLuint tex = setup_new_sprites_texture(texture_type);
|
||||
glTexStorage3D(texture_type, 1, GL_SRGB8_ALPHA8, width, height, znum);
|
||||
|
|
@ -223,8 +223,8 @@ send_sprite_to_gpu(FONTS_DATA_HANDLE fg, sprite_index idx, pixel *buf, sprite_in
|
|||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map->texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
sprite_index_to_pos(idx, xnum, ynum, &x, &y, &z);
|
||||
x *= fg->fcm.cell_width; y *= fg->fcm.cell_height;
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, fg->fcm.cell_width, fg->fcm.cell_height, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf);
|
||||
x *= fg->fcm.cell_width; y *= (fg->fcm.cell_height + 1);
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, fg->fcm.cell_width, fg->fcm.cell_height + 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -368,7 +368,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
|
|||
|
||||
GLuint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
|
||||
GLuint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx;
|
||||
GLuint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx, cell_height;
|
||||
GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity;
|
||||
GLuint bg_colors0, bg_colors1, bg_colors2, bg_colors3, bg_colors4, bg_colors5, bg_colors6, bg_colors7;
|
||||
GLfloat bg_opacities0, bg_opacities1, bg_opacities2, bg_opacities3, bg_opacities4, bg_opacities5, bg_opacities6, bg_opacities7;
|
||||
|
|
@ -459,6 +459,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
|
|||
sprite_tracker_current_layout(os_window->fonts_data, &x, &y, &z);
|
||||
rd->sprites_xnum = x; rd->sprites_ynum = y;
|
||||
rd->inverted = screen_invert_colors(screen) ? 1 : 0;
|
||||
rd->cell_height = os_window->fonts_data->fcm.cell_height;
|
||||
|
||||
#undef COLOR
|
||||
rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ class Rendering(FontBaseTest):
|
|||
|
||||
def test_sprite_map(self):
|
||||
sprite_map_set_limits(10, 3)
|
||||
sprite_map_set_layout(5, 5)
|
||||
sprite_map_set_layout(5, 4) # 4 because of underline_exclusion row
|
||||
self.ae(test_sprite_position_increment(), (0, 0, 0))
|
||||
self.ae(test_sprite_position_increment(), (1, 0, 0))
|
||||
self.ae(test_sprite_position_increment(), (0, 1, 0))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue