Skip to content

Commit

Permalink
Use the same algorithm for rendering box cells and font based cells
Browse files Browse the repository at this point in the history
Should make things easier to change in tandem in future.
  • Loading branch information
kovidgoyal committed Feb 19, 2025
1 parent 0c7dd7e commit 2907999
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 45 deletions.
86 changes: 41 additions & 45 deletions kitty/fonts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,76 +1030,69 @@ render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell,
ensure_glyph_render_scratch_space(64);
text_in_cell(cpu_cell, tc, global_glyph_render_scratch.lc);
ensure_glyph_render_scratch_space(rf.scale * global_glyph_render_scratch.lc->count);
unsigned num_glyphs = 0;
unsigned int ch = 0;
unsigned num_glyphs = 0, num_cells = rf.scale;
for (unsigned i = 0; i < global_glyph_render_scratch.lc->count; i++) {
glyph_index glyph = box_glyph_id(global_glyph_render_scratch.lc->chars[i]);
if (glyph != 0xffff) { ch = global_glyph_render_scratch.lc->chars[i] ;global_glyph_render_scratch.glyphs[num_glyphs++] = glyph; }
if (glyph != 0xffff) global_glyph_render_scratch.glyphs[num_glyphs++] = glyph;
else global_glyph_render_scratch.lc->chars[i] = 0;
}
#define failed {\
if (PyErr_Occurred()) PyErr_Print(); \
for (unsigned i = 0; i < rf.scale; i++) gpu_cell[i].sprite_idx = 0; \
for (unsigned i = 0; i < num_cells; i++) gpu_cell[i].sprite_idx = 0; \
return; \
}
if (!num_glyphs) failed;
bool all_rendered = true;
#define sp global_glyph_render_scratch.sprite_positions
for (unsigned ligature_index = 0; ligature_index < rf.scale; ligature_index++) {
sp[ligature_index] = sprite_position_for(fg, rf, global_glyph_render_scratch.glyphs, num_glyphs, ligature_index, rf.scale);
for (unsigned ligature_index = 0; ligature_index < num_cells; ligature_index++) {
sp[ligature_index] = sprite_position_for(fg, rf, global_glyph_render_scratch.glyphs, num_glyphs, ligature_index, num_cells);
if (sp[ligature_index] == NULL) failed;
sp[ligature_index]->colored = false;
if (!sp[ligature_index]->rendered) all_rendered = false;
}
if (all_rendered) {
for (unsigned i = 0; i < rf.scale; i++) set_cell_sprite(gpu_cell + i, sp[i]);
for (unsigned i = 0; i < num_cells; i++) set_cell_sprite(gpu_cell + i, sp[i]);
return;
}
FontCellMetrics unscaled_metrics = fg->fcm;
float scale = apply_scale_to_font_group(fg, &rf);
ensure_canvas_can_fit(fg, num_glyphs + 1, rf.scale);
FontCellMetrics scaled_metrics = fg->fcm;
unsigned width = fg->fcm.cell_width, height = fg->fcm.cell_height;
if (scale != 1) apply_scale_to_font_group(fg, NULL);
uint8_t *alpha_mask = NULL;
ensure_canvas_can_fit(fg, num_glyphs + 1, rf.scale); // in case size is larger scale is larger
if (num_glyphs == 1) {
render_box_char(ch, fg->canvas.alpha_mask, width, height, fg->logical_dpi_x, fg->logical_dpi_y, scale);
alpha_mask = fg->canvas.alpha_mask;
} else {
alpha_mask = ((uint8_t*)fg->canvas.buf) + fg->canvas.size_in_bytes - (num_glyphs * width * height);
unsigned cnum = 0;
for (unsigned i = 0; i < num_glyphs; i++) {
unsigned int ch = global_glyph_render_scratch.lc->chars[cnum++];
while (!ch) ch = global_glyph_render_scratch.lc->chars[cnum++];
render_box_char(ch, fg->canvas.alpha_mask, width, height, fg->logical_dpi_x, fg->logical_dpi_y, scale);
uint8_t *src = fg->canvas.alpha_mask;
for (unsigned y = 0; y < height; y++) {
uint8_t *dest_row = alpha_mask + y*num_glyphs*width + i*width;
memcpy(dest_row, src + y * width, width);
}
ensure_canvas_can_fit(fg, num_glyphs + 1, rf.scale); // in case unscaled size is larger is than scaled size
unsigned mask_stride = scaled_metrics.cell_width * num_glyphs, right_shift = 0;
if (rf.subscale_n && rf.subscale_d && rf.align.horizontal && scaled_metrics.cell_width <= unscaled_metrics.cell_width) {
int delta = unscaled_metrics.cell_width * num_cells - mask_stride;
if (rf.align.horizontal == 2) delta /= 2;
if (delta > 0) {
right_shift = delta;
mask_stride += delta;
}
}
width *= num_glyphs;
Region src = { .right = width, .bottom = height }, dest = src;
render_alpha_mask(alpha_mask, fg->canvas.buf, &src, &dest, width, width, 0xffffff);
/*printf("Rendered char sz: (%u, %u)\n", width, height); dump_sprite(fg->canvas.buf, width, height);*/
if (scale == 1.f && rf.scale == 1 && !rf.subscale_n) {
sp[0]->idx = current_send_sprite_to_gpu(fg, fg->canvas.buf, index_for_decorations(fg, rf, src, dest, scaled_metrics), scaled_metrics);
if (!sp[0]->idx) failed;
sp[0]->rendered = true;
set_cell_sprite(gpu_cell, sp[0]);
} else {
calculate_regions_for_line(rf, fg->fcm.cell_height, &src, &dest);
DecorationMetadata dm = index_for_decorations(fg, rf, src, dest, scaled_metrics);
/*printf("width: %u height: %u unscaled_cell_width: %u unscaled_cell_height: %u src.top: %u src.bottom: %u rf.scale: %u\n", width, height, fg->fcm.cell_width, fg->fcm.cell_height, src.top, src.bottom, rf.scale);*/
for (unsigned i = 0; i < rf.scale; i++) {
pixel *b = extract_cell_region(&fg->canvas, i, &src, &dest, width, fg->fcm);
Region src = {.right = scaled_metrics.cell_width, .bottom = scaled_metrics.cell_height }, dest = src;
for (unsigned i = 0, cnum = 0; i < num_glyphs; i++) {
unsigned int ch = global_glyph_render_scratch.lc->chars[cnum++];
while (!ch) ch = global_glyph_render_scratch.lc->chars[cnum++];
render_box_char(ch, fg->canvas.alpha_mask, src.right, src.bottom, fg->logical_dpi_x, fg->logical_dpi_y, scale);
dest.left = i * scaled_metrics.cell_width + right_shift; dest.right = dest.left + scaled_metrics.cell_width;
render_alpha_mask(fg->canvas.alpha_mask, fg->canvas.buf, &src, &dest, src.right, mask_stride, 0xffffff);
}
src.right = mask_stride; dest = src; dest.right = unscaled_metrics.cell_width * num_cells;
/*printf("Rendered char sz: (%u, %u)\n", src.right, src.bottom); dump_sprite(fg->canvas.buf, src.right, src.bottom);*/
calculate_regions_for_line(rf, unscaled_metrics.cell_height, &src, &dest);
DecorationMetadata dm = index_for_decorations(fg, rf, src, dest, scaled_metrics);
/*printf("width: %u height: %u unscaled_cell_width: %u unscaled_cell_height: %u src.top: %u src.bottom: %u num_cells: %u\n", width, height, fg->fcm.cell_width, fg->fcm.cell_height, src.top, src.bottom, num_cells);*/
for (unsigned i = 0; i < num_cells; i++) {
if (!sp[i]->rendered) {
pixel *b = extract_cell_region(&fg->canvas, i, &src, &dest, mask_stride, unscaled_metrics);
/*printf("cell %u src -> dest: (%u %u) -> (%u %u)\n", i, src.left, src.right, dest.left, dest.right);*/
sp[i]->idx = current_send_sprite_to_gpu(fg, b, dm, scaled_metrics);
if (!sp[i]->idx) failed;
sp[i]->rendered = true;
set_cell_sprite(gpu_cell + i, sp[i]);
/*printf("Sprite %u: pos: %u sz: (%u, %u)\n", i, sp[i]->idx, fg->fcm.cell_width, fg->fcm.cell_height); dump_sprite(b, fg->fcm.cell_width, fg->fcm.cell_height);*/
/*dump_sprite(b, unscaled_metrics.cell_width, unscaled_metrics.cell_height);*/
sp[i]->rendered = true; sp[i]->colored = false;
}
set_cell_sprite(gpu_cell + i, sp[i]);
/*printf("Sprite %u: pos: %u sz: (%u, %u)\n", i, sp[i]->idx, fg->fcm.cell_width, fg->fcm.cell_height); dump_sprite(b, fg->fcm.cell_width, fg->fcm.cell_height);*/
}
#undef sp
#undef failed
Expand Down Expand Up @@ -1153,6 +1146,8 @@ apply_horizontal_alignment(pixel *canvas, RunFont rf, bool center_glyph, GlyphRe
if (delta > 0) right_shift_canvas(canvas, ri.canvas_width, canvas_height, delta);
}



static void
render_group(
FontGroup *fg, unsigned int num_cells, unsigned int num_glyphs, CPUCell *cpu_cells, GPUCell *gpu_cells,
Expand Down Expand Up @@ -1195,15 +1190,16 @@ render_group(
for (unsigned i = 1; i < num_glyphs && is_only_filled_boxes; i++) if (global_glyph_render_scratch.glyphs[i] != box_glyph_id) is_only_filled_boxes = false;
}
/*printf("num_cells: %u num_scaled_cells: %u num_glyphs: %u scale: %f unscaled: %ux%u scaled: %ux%u\n", num_cells, num_scaled_cells, num_glyphs, scale, unscaled_metrics.cell_width, unscaled_metrics.cell_height, scaled_metrics.cell_width, scaled_metrics.cell_height);*/
GlyphRenderInfo ri = {0};
if (is_only_filled_boxes) { // special case rendering of █ for tests
render_filled_sprite(fg->canvas.buf, num_glyphs, scaled_metrics, num_scaled_cells);
was_colored = false;
ri.canvas_width = num_cells * unscaled_metrics.cell_width; ri.rendered_width = num_glyphs * scaled_metrics.cell_width;
/*dump_sprite(fg->canvas.buf, scaled_metrics.cell_width * num_scaled_cells, scaled_metrics.cell_height);*/
} else {
GlyphRenderInfo ri = {0};
render_glyphs_in_cells(font->face, font->bold, font->italic, info, positions, num_glyphs, fg->canvas.buf, scaled_metrics.cell_width, scaled_metrics.cell_height, num_scaled_cells, scaled_metrics.baseline, &was_colored, (FONTS_DATA_HANDLE)fg, &ri);
apply_horizontal_alignment(fg->canvas.buf, rf, center_glyph, ri, scaled_metrics.cell_height, num_scaled_cells, num_glyphs, was_colored);
}
apply_horizontal_alignment(fg->canvas.buf, rf, center_glyph, ri, scaled_metrics.cell_height, num_scaled_cells, num_glyphs, was_colored);
if (PyErr_Occurred()) PyErr_Print();

fg->fcm = unscaled_metrics; // needed for current_send_sprite_to_gpu()
Expand Down
1 change: 1 addition & 0 deletions kitty_tests/fonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ def scaled_drawing_test(self):
block_test(full_block)
block_test(full_block, full_block, full_block, full_block, scale=2)
block_test(full_block, empty_block, empty_block, empty_block, scale=2, subscale_n=1, subscale_d=2)
block_test(empty_block, full_block, empty_block, empty_block, scale=2, subscale_n=1, subscale_d=2, horizontal_align=1)
block_test(full_block, full_block, empty_block, empty_block, scale=2, subscale_n=1, subscale_d=2, text='██')
block_test(empty_block, empty_block, full_block, empty_block, scale=2, subscale_n=1, subscale_d=2, vertical_align=1)
block_test(quarter_block, scale=1, subscale_n=1, subscale_d=2)
Expand Down

0 comments on commit 2907999

Please sign in to comment.