mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
Implement horizontal alignment for font based rendering
Still need to do it for box chars
This commit is contained in:
parent
15f711d6b5
commit
0c7dd7edb2
4 changed files with 40 additions and 23 deletions
|
|
@ -1001,7 +1001,7 @@ render_single_ascii_char_as_mask(const char ch, size_t *result_width, size_t *re
|
|||
|
||||
|
||||
static bool
|
||||
do_render(CTFontRef ct_font, unsigned int units_per_em, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
||||
do_render(CTFontRef ct_font, unsigned int units_per_em, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONTS_DATA_HANDLE fg, GlyphRenderInfo *ri) {
|
||||
unsigned int canvas_width = cell_width * num_cells;
|
||||
ensure_render_space(canvas_width, cell_height, num_glyphs);
|
||||
CGRect br = CTFontGetBoundingRectsForGlyphs(ct_font, kCTFontOrientationHorizontal, buffers.glyphs, buffers.boxes, num_glyphs);
|
||||
|
|
@ -1015,7 +1015,7 @@ do_render(CTFontRef ct_font, unsigned int units_per_em, bool bold, bool italic,
|
|||
CGFloat sz = CTFontGetSize(ct_font);
|
||||
sz *= canvas_width / right;
|
||||
CTFontRef new_font = CTFontCreateCopyWithAttributes(ct_font, sz, NULL, NULL);
|
||||
bool ret = do_render(new_font, CTFontGetUnitsPerEm(new_font), bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, false, fg, center_glyph);
|
||||
bool ret = do_render(new_font, CTFontGetUnitsPerEm(new_font), bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, false, fg, ri);
|
||||
CFRelease(new_font);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1037,23 +1037,18 @@ do_render(CTFontRef ct_font, unsigned int units_per_em, bool bold, bool italic,
|
|||
Region src = {.bottom=cell_height, .right=canvas_width}, dest = {.bottom=cell_height, .right=canvas_width};
|
||||
render_alpha_mask(buffers.render_buf, canvas, &src, &dest, canvas_width, canvas_width, 0xffffff);
|
||||
}
|
||||
if (num_cells && (center_glyph || (num_cells == 2 && *was_colored))) {
|
||||
if (debug_rendering) printf("centering glyphs: center_glyph: %d\n", center_glyph);
|
||||
// center glyphs (two cell emoji, PUA glyphs, ligatures, etc)
|
||||
CGFloat delta = (((CGFloat)canvas_width - br.size.width) / 2.f);
|
||||
// FiraCode ligatures result in negative origins
|
||||
if (br.origin.x > 0) delta -= br.origin.x;
|
||||
if (delta >= 1.f) right_shift_canvas(canvas, canvas_width, cell_height, (unsigned)(delta));
|
||||
}
|
||||
ri->canvas_width = canvas_width; ri->rendered_width = (unsigned)ceil(br.size.width); ri->x = 0;
|
||||
// FiraCode ligatures result in negative origins
|
||||
if (br.origin.x > 0) ri->x = (int)br.origin.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
||||
render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, GlyphRenderInfo *ri) {
|
||||
CTFace *self = (CTFace*)s;
|
||||
ensure_render_space(128, 128, num_glyphs);
|
||||
for (unsigned i=0; i < num_glyphs; i++) buffers.glyphs[i] = info[i].codepoint;
|
||||
return do_render(self->ct_font, self->units_per_em, bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, true, fg, center_glyph);
|
||||
return do_render(self->ct_font, self->units_per_em, bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, true, fg, ri);
|
||||
}
|
||||
|
||||
// Font tables {{{
|
||||
|
|
|
|||
|
|
@ -1135,6 +1135,24 @@ render_filled_sprite(pixel *buf, unsigned num_glyphs, FontCellMetrics scaled_met
|
|||
} else memset(buf, 0xff, sizeof(buf[0]) * num_glyphs * scaled_metrics.cell_height * scaled_metrics.cell_width );
|
||||
}
|
||||
|
||||
static void
|
||||
apply_horizontal_alignment(pixel *canvas, RunFont rf, bool center_glyph, GlyphRenderInfo ri, unsigned canvas_height, unsigned num_cells, unsigned num_glyphs, bool was_colored) {
|
||||
int delta = 0;
|
||||
(void)was_colored;
|
||||
#ifdef __APPLE__
|
||||
if (num_cells == 2 && was_colored) center_glyph = true;
|
||||
#endif
|
||||
if (rf.subscale_n && rf.subscale_d && rf.align.horizontal) {
|
||||
delta = ri.canvas_width - ri.rendered_width;
|
||||
if (rf.align.horizontal == 2) delta /= 2;
|
||||
} else if (center_glyph && num_glyphs && num_cells > 1 && ri.rendered_width < ri.canvas_width) {
|
||||
unsigned half = (ri.canvas_width - ri.rendered_width) / 2;
|
||||
if (half > 1) delta = half;
|
||||
}
|
||||
delta -= ri.x;
|
||||
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,
|
||||
|
|
@ -1181,7 +1199,11 @@ render_group(
|
|||
render_filled_sprite(fg->canvas.buf, num_glyphs, scaled_metrics, num_scaled_cells);
|
||||
was_colored = false;
|
||||
/*dump_sprite(fg->canvas.buf, scaled_metrics.cell_width * num_scaled_cells, scaled_metrics.cell_height);*/
|
||||
} else 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, center_glyph);
|
||||
} 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);
|
||||
}
|
||||
if (PyErr_Occurred()) PyErr_Print();
|
||||
|
||||
fg->fcm = unscaled_metrics; // needed for current_send_sprite_to_gpu()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ typedef struct ParsedFontFeature {
|
|||
bool hash_computed;
|
||||
} ParsedFontFeature;
|
||||
|
||||
typedef struct GlyphRenderInfo {
|
||||
unsigned canvas_width, rendered_width;
|
||||
int x;
|
||||
} GlyphRenderInfo;
|
||||
|
||||
ParsedFontFeature* parse_font_feature(const char *spec);
|
||||
|
||||
// API that font backends need to implement
|
||||
|
|
@ -40,7 +45,7 @@ bool is_glyph_empty(PyObject *, glyph_index);
|
|||
hb_font_t* harfbuzz_font_for_face(PyObject*);
|
||||
bool set_size_for_face(PyObject*, unsigned int, bool, FONTS_DATA_HANDLE);
|
||||
FontCellMetrics cell_metrics(PyObject*);
|
||||
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, bool center_glyph);
|
||||
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, GlyphRenderInfo*);
|
||||
PyObject* create_fallback_face(PyObject *base_face, const ListOfChars *lc, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg);
|
||||
PyObject* specialize_font_descriptor(PyObject *base_descriptor, double, double, double);
|
||||
PyObject* face_from_path(const char *path, int index, FONTS_DATA_HANDLE);
|
||||
|
|
|
|||
|
|
@ -960,7 +960,7 @@ place_bitmap_in_canvas(pixel *cell, ProcessedBitmap *bm, size_t cell_width, size
|
|||
static const ProcessedBitmap EMPTY_PBM = {.factor = 1};
|
||||
|
||||
bool
|
||||
render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
||||
render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, GlyphRenderInfo *ri) {
|
||||
Face *self = (Face*)f;
|
||||
bool is_emoji = *was_colored; *was_colored = is_emoji && self->has_color;
|
||||
float x = 0.f, y = 0.f, x_offset = 0.f;
|
||||
|
|
@ -1003,14 +1003,9 @@ render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *inf
|
|||
free_processed_bitmap(&bm);
|
||||
}
|
||||
|
||||
if (center_glyph && num_glyphs) {
|
||||
unsigned int right_edge = (unsigned int)x, delta;
|
||||
// x_advance is wrong for colored bitmaps that have been downsampled
|
||||
if (*was_colored) right_edge = num_glyphs == 1 ? bm.right_edge : canvas_width;
|
||||
if (num_cells > 1 && right_edge < canvas_width && (delta = (canvas_width - right_edge) / 2) && delta > 1) {
|
||||
right_shift_canvas(canvas, canvas_width, cell_height, delta);
|
||||
}
|
||||
}
|
||||
ri->canvas_width = canvas_width; ri->rendered_width = (unsigned)x; ri->x = 0;
|
||||
// x_advance is wrong for colored bitmaps that have been downsampled
|
||||
if (*was_colored) ri->rendered_width = num_glyphs == 1 ? bm.right_edge : canvas_width;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue