From aef002e0d92caeed512ae1f40904d02ebcb8d506 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 7 Feb 2023 11:29:49 -0700 Subject: [PATCH] [embolden] Add in-place option Adds --font-grade to hb-view and hb-shape. --- src/hb-font.cc | 44 ++++++++++++++++++++++++++++++-------------- src/hb-font.h | 8 ++++++-- src/hb-font.hh | 9 +++++---- src/hb-ft.cc | 43 +++++++++++++++++++++++++++++++++++++------ src/hb-ot-font.cc | 22 ++++++++++++++-------- src/hb-outline.cc | 7 ++++--- src/hb-outline.hh | 3 ++- util/font-options.hh | 37 ++++++++++++++++++++++++++++++++----- 8 files changed, 130 insertions(+), 43 deletions(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index 715042d0d..a3d394f87 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1774,8 +1774,9 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* y_scale */ 0.f, /* x_embolden */ 0.f, /* y_embolden */ - 0, /* x_shift */ - 0, /* y_shift */ + true, /* embolden_in_place */ + 0, /* x_strength */ + 0, /* y_strength */ 0.f, /* slant */ 0.f, /* slant_xy; */ 1.f, /* x_multf */ @@ -1815,6 +1816,7 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = face->get_upem (); + font->embolden_in_place = true; font->x_multf = font->y_multf = 1.f; font->x_mult = font->y_mult = 1 << 16; font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE; @@ -1901,6 +1903,7 @@ hb_font_create_sub_font (hb_font_t *parent) font->y_scale = parent->y_scale; font->x_embolden = parent->x_embolden; font->y_embolden = parent->y_embolden; + font->embolden_in_place = parent->embolden_in_place; font->slant = parent->slant; font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -2453,54 +2456,67 @@ hb_font_get_ptem (hb_font_t *font) * @font: #hb_font_t to work upon * @x_embolden: the amount to embolden horizontally * @y_embolden: the amount to embolden vertically + * @in_place: whether to embolden glyphs in-place * * Sets the "synthetic boldness" of a font. * - * Positive values make a font bolder, negative values - * thinner. Typical values are in the 0.01 to 0.05 range. - * The default value is zero. + * Positive values for @x_embolden / @y_embolden make a font + * bolder, negative values thinner. Typical values are in the + * 0.01 to 0.05 range. The default value is zero. * * Synthetic boldness is applied by offsetting the contour * points of the glyph shape. * - * HarfBuzz applies synthetic boldness when rendering a glyph - * via hb_font_draw_glyph(), and also uses the values to adjust - * the advance width of emboldened glyphs. + * Synthetic boldness is applied when rendering a glyph via + * hb_font_draw_glyph(). + * + * If @in_place is %FALSE, then glyph advance-widths are also + * adjusted, otherwise they are not. * * Since: REPLACEME **/ void -hb_font_set_synthetic_bold (hb_font_t *font, float x_embolden, float y_embolden) +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, + float y_embolden, + hb_bool_t in_place) { if (hb_object_is_immutable (font)) return; if (font->x_embolden == x_embolden && - font->y_embolden == y_embolden) + font->y_embolden == y_embolden && + font->embolden_in_place == in_place) return; font->serial++; font->x_embolden = x_embolden; font->y_embolden = y_embolden; + font->embolden_in_place = in_place; font->mults_changed (); } /** * hb_font_get_synthetic_bold: * @font: #hb_font_t to work upon - * @x_embolden: return location for horizontal value - * @y_embolden: return location for vertical value + * @x_embolden: (out): return location for horizontal value + * @y_embolden: (out): return location for vertical value + * @in_place: (out): return location for in-place value * - * Fetches the "synthetic boldness" of a font. + * Fetches the "synthetic boldness" parameters of a font. * * Since: REPLACEME **/ void -hb_font_get_synthetic_bold (hb_font_t *font, float *x_embolden, float *y_embolden) +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, + float *y_embolden, + hb_bool_t *in_place) { if (x_embolden) *x_embolden = font->x_embolden; if (y_embolden) *y_embolden = font->y_embolden; + if (in_place) *in_place = font->embolden_in_place; } /** diff --git a/src/hb-font.h b/src/hb-font.h index f90b6e20b..f5d79e3f0 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -1132,10 +1132,14 @@ HB_EXTERN float hb_font_get_ptem (hb_font_t *font); HB_EXTERN void -hb_font_set_synthetic_bold (hb_font_t *font, float x_embolden, float y_embolden); +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, float y_embolden, + hb_bool_t in_place); HB_EXTERN void -hb_font_get_synthetic_bold (hb_font_t *font, float *x_embolden, float *y_embolden); +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, float *y_embolden, + hb_bool_t *in_place); HB_EXTERN void hb_font_set_synthetic_slant (hb_font_t *font, float slant); diff --git a/src/hb-font.hh b/src/hb-font.hh index 767382e7c..4520c7885 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -116,8 +116,9 @@ struct hb_font_t float x_embolden; float y_embolden; - int32_t x_shift; /* x_embolden, in scaled units. */ - int32_t y_shift; /* y_embolden, in scaled units. */ + bool embolden_in_place; + int32_t x_strength; /* x_embolden, in scaled units. */ + int32_t y_strength; /* y_embolden, in scaled units. */ float slant; float slant_xy; @@ -681,8 +682,8 @@ struct hb_font_t bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; - x_shift = fabs (roundf (x_scale * x_embolden)); - y_shift = fabs (roundf (y_scale * y_embolden)); + x_strength = fabs (roundf (x_scale * x_embolden)); + y_strength = fabs (roundf (y_scale * y_embolden)); slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 064fff15d..af15c9e63 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -490,14 +490,14 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } - if (font->x_shift) + if (font->x_strength && !font->embolden_in_place) { /* Emboldening. */ - hb_position_t x_shift = font->x_scale >= 0 ? font->x_shift : -font->x_shift; + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; first_advance = orig_first_advance; for (unsigned int i = 0; i < count; i++) { - *first_advance += *first_advance ? x_shift : 0; + *first_advance += *first_advance ? x_strength : 0; first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } @@ -536,8 +536,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ - hb_position_t y_shift = font->y_scale >= 0 ? font->y_shift : -font->y_shift; - return ((-v + (1<<9)) >> 10) + y_shift; + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); } #endif @@ -858,7 +858,38 @@ hb_ft_draw_glyph (hb_font_t *font, hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); - FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_shift, font->y_shift); + /* Embolden */ + if (font->x_strength || font->y_strength) + { + FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength); + + int x_shift = 0; + int y_shift = 0; + if (font->embolden_in_place) + { + /* Undo the FreeType shift. */ + x_shift = -font->x_strength / 2; + y_shift = 0; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + else + { + /* FreeType applied things in the wrong direction for negative scale; fix up. */ + if (font->x_scale < 0) x_shift = -font->x_strength; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + if (x_shift || y_shift) + { + auto &outline = ft_face->glyph->outline; + for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1])) + { + point.x += x_shift; + point.y += y_shift; + } + } + } + + FT_Outline_Decompose (&ft_face->glyph->outline, &outline_funcs, &draw_session); diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 6cfe8cf56..41c8c1f6d 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -262,14 +262,14 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, OT::VariationStore::destroy_cache (varStore_cache); #endif - if (font->x_shift) + if (font->x_strength && !font->embolden_in_place) { /* Emboldening. */ - hb_position_t x_shift = font->x_scale >= 0 ? font->x_shift : -font->x_shift; + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; first_advance = orig_first_advance; for (unsigned int i = 0; i < count; i++) { - *first_advance += *first_advance ? x_shift : 0; + *first_advance += *first_advance ? x_strength : 0; first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } @@ -326,14 +326,14 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, } } - if (font->y_shift) + if (font->y_strength && !font->embolden_in_place) { /* Emboldening. */ - hb_position_t y_shift = font->y_scale >= 0 ? font->y_shift : -font->y_shift; + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; first_advance = orig_first_advance; for (unsigned int i = 0; i < count; i++) { - *first_advance += *first_advance ? y_shift : 0; + *first_advance += *first_advance ? y_strength : 0; first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } @@ -492,7 +492,7 @@ hb_ot_draw_glyph (hb_font_t *font, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data) { - bool embolden = font->x_shift || font->y_shift; + bool embolden = font->x_strength || font->y_strength; hb_outline_t outline; { // Need draw_session to be destructed before emboldening. @@ -508,7 +508,13 @@ hb_ot_draw_glyph (hb_font_t *font, if (embolden) { - outline.embolden (font->x_shift, font->y_shift); + float x_shift = font->embolden_in_place ? 0 : font->x_strength / 2; + float y_shift = font->y_strength / 2; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->y_scale < 0) y_shift = -y_shift; + outline.embolden (font->x_strength, font->y_strength, + x_shift, y_shift); + outline.replay (draw_funcs, draw_data); } } diff --git a/src/hb-outline.cc b/src/hb-outline.cc index 1cf166336..184e48cfb 100644 --- a/src/hb-outline.cc +++ b/src/hb-outline.cc @@ -105,7 +105,8 @@ float hb_outline_t::area () const return a * .5f; } -void hb_outline_t::embolden (float x_strength, float y_strength) +void hb_outline_t::embolden (float x_strength, float y_strength, + float x_shift, float y_shift) { /* This function is a straight port of FreeType's FT_Outline_EmboldenXY. * Permission has been obtained from the FreeType authors of the code @@ -203,8 +204,8 @@ void hb_outline_t::embolden (float x_strength, float y_strength) i != j; i = i < last ? i + 1 : first ) { - points[i].x += x_strength + shift.x; - points[i].y += y_strength + shift.y; + points[i].x += x_shift + shift.x; + points[i].y += y_shift + shift.y; } } else diff --git a/src/hb-outline.hh b/src/hb-outline.hh index ffb3e52d1..c463993cf 100644 --- a/src/hb-outline.hh +++ b/src/hb-outline.hh @@ -69,7 +69,8 @@ struct hb_outline_t HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const; HB_INTERNAL float area () const; - HB_INTERNAL void embolden (float x_strength, float y_strength); + HB_INTERNAL void embolden (float x_strength, float y_strength, + float x_shift, float y_shift); hb_vector_t points; hb_vector_t contours; diff --git a/util/font-options.hh b/util/font-options.hh index 5b5de2265..8ec36c97e 100644 --- a/util/font-options.hh +++ b/util/font-options.hh @@ -65,6 +65,7 @@ struct font_options_t : face_options_t double ptem = 0.; double x_embolden = 0.; double y_embolden = 0.; + hb_bool_t embolden_in_place = false; double slant = 0.; unsigned int subpixel_bits = SUBPIXEL_BITS; mutable double font_size_x = DEFAULT_FONT_SIZE; @@ -103,7 +104,9 @@ font_options_t::post_parse (GError **error) hb_font_set_ppem (font, x_ppem, y_ppem); hb_font_set_ptem (font, ptem); - hb_font_set_synthetic_bold (font, (float) x_embolden, (float) y_embolden); + hb_font_set_synthetic_bold (font, + (float) x_embolden, (float) y_embolden, + embolden_in_place); hb_font_set_synthetic_slant (font, slant); int scale_x = (int) scalbnf (font_size_x, subpixel_bits); @@ -249,10 +252,10 @@ parse_font_ppem (const char *name G_GNUC_UNUSED, } static gboolean -parse_font_bold (const char *name G_GNUC_UNUSED, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) +parse_font_embolden (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { font_options_t *font_opts = (font_options_t *) data; switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->x_embolden, &font_opts->y_embolden)) { @@ -266,6 +269,28 @@ parse_font_bold (const char *name G_GNUC_UNUSED, } } +static gboolean +parse_font_bold (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + font_options_t *font_opts = (font_options_t *) data; + font_opts->embolden_in_place = false; + return parse_font_embolden ( name, arg, data, error); +} + +static gboolean +parse_font_grade (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + font_options_t *font_opts = (font_options_t *) data; + font_opts->embolden_in_place = true; + return parse_font_embolden ( name, arg, data, error); +} + void font_options_t::add_options (option_parser_t *parser) { @@ -309,6 +334,8 @@ font_options_t::add_options (option_parser_t *parser) G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"}, {"font-bold", 0, font_size_flags, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_bold, "Set synthetic bold (default: 0)", "1/2 numbers; eg. 0.05"}, + {"font-grade", 0, font_size_flags, + G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_grade, "Set synthetic grade (default: 0)", "1/2 numbers; eg. 0.05"}, {"font-slant", 0, font_size_flags, G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"}, {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},