Adjust the point size of fallback and symbol fonts so that their heights match the current cell height

This commit is contained in:
Kovid Goyal 2017-11-12 10:30:57 +05:30
parent 604e82fd65
commit 67a37f1f41
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 30 additions and 23 deletions

View File

@ -218,8 +218,8 @@ python_send_to_gpu(unsigned int x, unsigned int y, unsigned int z, uint8_t* buf)
static inline PyObject* static inline PyObject*
update_cell_metrics() { update_cell_metrics() {
#define CALL(f, desired_height) { if ((f)->face) { if(!set_size_for_face((f)->face, desired_height)) return NULL; (f)->hb_font = harfbuzz_font_for_face((f)->face); } clear_sprite_map((f)); } #define CALL(f, desired_height, force) { if ((f)->face) { if(!set_size_for_face((f)->face, desired_height, force)) return NULL; (f)->hb_font = harfbuzz_font_for_face((f)->face); } clear_sprite_map((f)); }
CALL(&medium_font, 0); CALL(&bold_font, 0); CALL(&italic_font, 0); CALL(&bi_font, 0); CALL(&box_font, 0); CALL(&medium_font, 0, false); CALL(&bold_font, 0, false); CALL(&italic_font, 0, false); CALL(&bi_font, 0, false); CALL(&box_font, 0, false);
cell_metrics(medium_font.face, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness); cell_metrics(medium_font.face, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness);
if (!cell_width) { PyErr_SetString(PyExc_ValueError, "Failed to calculate cell width for the specified font."); return NULL; } if (!cell_width) { PyErr_SetString(PyExc_ValueError, "Failed to calculate cell width for the specified font."); return NULL; }
if (OPT(adjust_line_height_px) != 0) cell_height += OPT(adjust_line_height_px); if (OPT(adjust_line_height_px) != 0) cell_height += OPT(adjust_line_height_px);
@ -232,10 +232,10 @@ update_cell_metrics() {
free(canvas); canvas = malloc(CELLS_IN_CANVAS * cell_width * cell_height); free(canvas); canvas = malloc(CELLS_IN_CANVAS * cell_width * cell_height);
if (canvas == NULL) return PyErr_NoMemory(); if (canvas == NULL) return PyErr_NoMemory();
for (size_t i = 0; fallback_fonts[i].face != NULL; i++) { for (size_t i = 0; fallback_fonts[i].face != NULL; i++) {
CALL(fallback_fonts + i, cell_height); CALL(fallback_fonts + i, cell_height, true);
} }
for (size_t i = 0; i < symbol_map_fonts_count; i++) { for (size_t i = 0; i < symbol_map_fonts_count; i++) {
CALL(symbol_map_fonts + i, cell_height); CALL(symbol_map_fonts + i, cell_height, true);
} }
return Py_BuildValue("IIIII", cell_width, cell_height, baseline, underline_position, underline_thickness); return Py_BuildValue("IIIII", cell_width, cell_height, baseline, underline_position, underline_thickness);
#undef CALL #undef CALL
@ -279,7 +279,7 @@ fallback_font(Cell *cell) {
if (face == NULL) { PyErr_Print(); return NULL; } if (face == NULL) { PyErr_Print(); return NULL; }
if (face == Py_None) { Py_DECREF(face); return NULL; } if (face == Py_None) { Py_DECREF(face); return NULL; }
if (!alloc_font(fallback_fonts + i, face, bold, italic, true)) { Py_DECREF(face); fatal("Out of memory"); } if (!alloc_font(fallback_fonts + i, face, bold, italic, true)) { Py_DECREF(face); fatal("Out of memory"); }
set_size_for_face(face, cell_height); set_size_for_face(face, cell_height, true);
Py_DECREF(face); Py_DECREF(face);
return fallback_fonts + i; return fallback_fonts + i;
} }

View File

@ -16,7 +16,7 @@
bool face_has_codepoint(PyObject *, char_type); bool face_has_codepoint(PyObject *, char_type);
hb_font_t* harfbuzz_font_for_face(PyObject*); hb_font_t* harfbuzz_font_for_face(PyObject*);
bool set_size_for_face(PyObject*, unsigned int); bool set_size_for_face(PyObject*, unsigned int, bool);
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*); void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
void sprite_tracker_current_layout(unsigned int *x, unsigned int *y, unsigned int *z); void sprite_tracker_current_layout(unsigned int *x, unsigned int *y, unsigned int *z);
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, uint8_t *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline); 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, uint8_t *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline);

View File

@ -70,10 +70,22 @@ set_freetype_error(const char* prefix, int err_code) {
static FT_Library library; static FT_Library library;
#define CALC_CELL_HEIGHT(self) font_units_to_pixels(self, self->height)
static inline int
font_units_to_pixels(Face *self, int x) {
return ceil((double)FT_MulFix(x, self->face->size->metrics.y_scale) / 64.0);
}
static inline bool static inline bool
set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt xdpi, FT_UInt ydpi) { set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt xdpi, FT_UInt ydpi, unsigned int desired_height) {
int error = FT_Set_Char_Size(self->face, char_width, char_height, xdpi, ydpi); int error = FT_Set_Char_Size(self->face, 0, char_height, xdpi, ydpi);
if (!error) { if (!error) {
unsigned int ch = CALC_CELL_HEIGHT(self);
if (desired_height && ch != desired_height) {
FT_F26Dot6 h = floor((double)char_height * (double)desired_height / (double) ch);
return set_font_size(self, 0, h, xdpi, ydpi, 0);
}
self->char_width = char_width; self->char_height = char_height; self->xdpi = xdpi; self->ydpi = ydpi; self->char_width = char_width; self->char_height = char_height; self->xdpi = xdpi; self->ydpi = ydpi;
if (self->harfbuzz_font != NULL) { if (self->harfbuzz_font != NULL) {
#ifdef HARFBUZZ_HAS_CHANGE_FONT #ifdef HARFBUZZ_HAS_CHANGE_FONT
@ -89,7 +101,7 @@ set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt
} else { } else {
if (!self->is_scalable && self->face->num_fixed_sizes > 0) { if (!self->is_scalable && self->face->num_fixed_sizes > 0) {
int32_t min_diff = INT32_MAX; int32_t min_diff = INT32_MAX;
int desired_height = global_state.cell_height; if (desired_height == 0) desired_height = global_state.cell_height;
if (desired_height == 0) { if (desired_height == 0) {
desired_height = ceil(((double)char_height / 64.) * (double)ydpi / 72.); desired_height = ceil(((double)char_height / 64.) * (double)ydpi / 72.);
desired_height += ceil(0.2 * desired_height); desired_height += ceil(0.2 * desired_height);
@ -97,7 +109,7 @@ set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt
FT_Int strike_index = -1; FT_Int strike_index = -1;
for (FT_Int i = 0; i < self->face->num_fixed_sizes; i++) { for (FT_Int i = 0; i < self->face->num_fixed_sizes; i++) {
int h = self->face->available_sizes[i].height; int h = self->face->available_sizes[i].height;
int32_t diff = h < desired_height ? desired_height - h : h - desired_height; int32_t diff = h < (int32_t)desired_height ? (int32_t)desired_height - h : h - (int32_t)desired_height;
if (diff < min_diff) { if (diff < min_diff) {
min_diff = diff; min_diff = diff;
strike_index = i; strike_index = i;
@ -116,12 +128,12 @@ set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt
} }
bool bool
set_size_for_face(PyObject *s, unsigned int UNUSED desired_height) { set_size_for_face(PyObject *s, unsigned int desired_height, bool force) {
Face *self = (Face*)s; Face *self = (Face*)s;
FT_UInt w = (FT_UInt)(ceil(global_state.font_sz_in_pts * 64.0)); FT_UInt w = (FT_UInt)(ceil(global_state.font_sz_in_pts * 64.0)), xdpi = (FT_UInt)global_state.logical_dpi_x, ydpi = (FT_UInt)global_state.logical_dpi_y;
if (self->char_width == w && self->char_height == w && self->xdpi == (FT_UInt)global_state.logical_dpi_x && self->ydpi == (FT_UInt)global_state.logical_dpi_x) return true; if (!force && (self->char_width == w && self->char_height == w && self->xdpi == xdpi && self->ydpi == ydpi)) return true;
((Face*)self)->size_in_pts = global_state.font_sz_in_pts; ((Face*)self)->size_in_pts = global_state.font_sz_in_pts;
return set_font_size(self, w, w, (FT_UInt)global_state.logical_dpi_x, (FT_UInt)global_state.logical_dpi_y); return set_font_size(self, w, w, xdpi, ydpi, desired_height);
} }
static inline int static inline int
@ -142,7 +154,7 @@ init_ft_face(Face *self, PyObject *path, int hinting, int hintstyle) {
#undef CPY #undef CPY
self->is_scalable = FT_IS_SCALABLE(self->face); self->is_scalable = FT_IS_SCALABLE(self->face);
self->hinting = hinting; self->hintstyle = hintstyle; self->hinting = hinting; self->hintstyle = hintstyle;
if (!set_size_for_face((PyObject*)self, 0)) return false; if (!set_size_for_face((PyObject*)self, 0, false)) return false;
self->harfbuzz_font = hb_ft_font_create(self->face, NULL); self->harfbuzz_font = hb_ft_font_create(self->face, NULL);
if (self->harfbuzz_font == NULL) { PyErr_NoMemory(); return false; } if (self->harfbuzz_font == NULL) { PyErr_NoMemory(); return false; }
hb_ft_font_set_load_flags(self->harfbuzz_font, get_load_flags(self->hinting, self->hintstyle, FT_LOAD_DEFAULT)); hb_ft_font_set_load_flags(self->harfbuzz_font, get_load_flags(self->hinting, self->hintstyle, FT_LOAD_DEFAULT));
@ -273,16 +285,11 @@ calc_cell_width(Face *self) {
return ans; return ans;
} }
static inline int
font_units_to_pixels(Face *self, int x) {
return ceil((double)FT_MulFix(x, self->face->size->metrics.y_scale) / 64.0);
}
void void
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) { cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) {
Face *self = (Face*)s; Face *self = (Face*)s;
*cell_width = calc_cell_width(self); *cell_width = calc_cell_width(self);
*cell_height = font_units_to_pixels(self, self->height); *cell_height = CALC_CELL_HEIGHT(self);
#ifdef __APPLE__ #ifdef __APPLE__
// See https://stackoverflow.com/questions/5511830/how-does-line-spacing-work-in-core-text-and-why-is-it-different-from-nslayoutm // See https://stackoverflow.com/questions/5511830/how-does-line-spacing-work-in-core-text-and-why-is-it-different-from-nslayoutm
if (self->apple_leading <= 0) { if (self->apple_leading <= 0) {
@ -344,9 +351,9 @@ render_bitmap(Face *self, int glyph_id, ProcessedBitmap *ans, unsigned int cell_
} else if (rescale && self->is_scalable && extra > MAX(2, cell_width / 3)) { } else if (rescale && self->is_scalable && extra > MAX(2, cell_width / 3)) {
FT_F26Dot6 char_width = self->char_width, char_height = self->char_height; FT_F26Dot6 char_width = self->char_width, char_height = self->char_height;
float ar = (float)max_width / (float)bitmap->width; float ar = (float)max_width / (float)bitmap->width;
if (set_font_size(self, (FT_F26Dot6)((float)self->char_width * ar), (FT_F26Dot6)((float)self->char_height * ar), self->xdpi, self->ydpi)) { if (set_font_size(self, (FT_F26Dot6)((float)self->char_width * ar), (FT_F26Dot6)((float)self->char_height * ar), self->xdpi, self->ydpi, 0)) {
if (!render_bitmap(self, glyph_id, ans, cell_width, num_cells, bold, italic, false)) return false; if (!render_bitmap(self, glyph_id, ans, cell_width, num_cells, bold, italic, false)) return false;
if (!set_font_size(self, char_width, char_height, self->xdpi, self->ydpi)) return false; if (!set_font_size(self, char_width, char_height, self->xdpi, self->ydpi, 0)) return false;
} else return false; } else return false;
} }
} }