From 9454bad89162158ab1ef91689f989b8f53754297 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 11 Mar 2024 23:34:43 -0400 Subject: [PATCH] gsk: Rework font reloading again Make a single gsk_reload_font helper that can tweak both scale and font options, so we can ensure that our scaled font has hint-metrics turned off (pango pays attention to hint metrics when sizing and rendering hex boxes, and that hurts us. --- gsk/gpu/gskgpudevice.c | 8 ++- gsk/gskprivate.c | 131 +++++++++++--------------------------- gsk/gskprivate.h | 11 ++-- gsk/gskrendernodeparser.c | 2 +- 4 files changed, 51 insertions(+), 101 deletions(-) diff --git a/gsk/gpu/gskgpudevice.c b/gsk/gpu/gskgpudevice.c index 49d1f316ac..c76e1480a2 100644 --- a/gsk/gpu/gskgpudevice.c +++ b/gsk/gpu/gskgpudevice.c @@ -918,7 +918,13 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self, return cache->image; } - scaled_font = gsk_get_scaled_font (font, scale); + /* Note: we want to scale the font to the required size *and* ensure that + * metrics hinting is off. The latter is necessary since pango lets metrics + * hinting influence the rendering of hexboxes, and we get bad outcomes if + * that happens. + */ + scaled_font = gsk_reload_font (font, scale, CAIRO_HINT_METRICS_OFF, CAIRO_HINT_STYLE_DEFAULT, CAIRO_ANTIALIAS_DEFAULT); + subpixel_x = (flags & 3) / 4.f; subpixel_y = ((flags >> 2) & 3) / 4.f; pango_font_get_glyph_extents (scaled_font, glyph, &ink_rect, NULL); diff --git a/gsk/gskprivate.c b/gsk/gskprivate.c index c3f45fc58e..0ce4ab2898 100644 --- a/gsk/gskprivate.c +++ b/gsk/gskprivate.c @@ -22,103 +22,27 @@ gsk_ensure_resources (void) } /*< private > - * gsk_get_scaled_font: - * @font: a `PangoFont` - * @scale: the scale - * - * Returns a font that is just like @font, at a size that - * is multiplied by @scale. - * - * Returns: (transfer full): a scaled version of @font - */ -PangoFont * -gsk_get_scaled_font (PangoFont *font, - float scale) -{ - if (scale == 1.0) - return g_object_ref (font); - -#if PANGO_VERSION_CHECK (1, 52, 0) - return pango_font_map_reload_font (pango_font_get_font_map (font), font, scale, NULL, NULL); -#else - GHashTable *fonts; - int key; - PangoFont *font2; - PangoFontDescription *desc; - int size; - PangoFontMap *fontmap; - PangoContext *context; - cairo_scaled_font_t *sf; - cairo_font_options_t *options; - FcPattern *pattern; - double dpi; - - key = (int) floor (scale * PANGO_SCALE + .5); - - fonts = (GHashTable *) g_object_get_data (G_OBJECT (font), "gsk-scaled-fonts"); - - if (fonts) - { - font2 = g_hash_table_lookup (fonts, GINT_TO_POINTER (key)); - if (font2) - return g_object_ref (font2); - } - else - { - fonts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); - g_object_set_data_full (G_OBJECT (font), "gsk-scaled-fonts", - fonts, (GDestroyNotify) g_hash_table_unref); - } - - desc = pango_font_describe (font); - size = pango_font_description_get_size (desc); - - if (pango_font_description_get_size_is_absolute (desc)) - pango_font_description_set_absolute_size (desc, size * scale); - else - pango_font_description_set_size (desc, (int) floor (size * scale + .5)); - - fontmap = pango_font_get_font_map (font); - context = pango_font_map_create_context (fontmap); - - sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font)); - options = cairo_font_options_create (); - cairo_scaled_font_get_font_options (sf, options); - pango_cairo_context_set_font_options (context, options); - cairo_font_options_destroy (options); - - pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font)); - if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) == FcResultMatch) - pango_cairo_context_set_resolution (context, dpi); - - font2 = pango_font_map_load_font (fontmap, context, desc); - - pango_font_description_free (desc); - g_object_unref (context); - - g_hash_table_insert (fonts, GINT_TO_POINTER (key), font2); - - return g_object_ref (font2); -#endif -} - -/*< private > - * gsk_get_hinted_font: + * gsk_reload_font: * @font: a `PangoFont` + * @scale: the scale to apply + * @hint_metris: hint metrics to use or `CAIRO_HINT_METRICS_DEFAILT` to keep the + * hint metrics of the font unchanged * @hint_style: hint style to use or `CAIRO_HINT_STYLE_DEFAULT` to keep the * hint style of @font unchanged * @antialias: antialiasing to use, or `CAIRO_ANTIALIAS_DEFAULT` to keep the * antialias option of @font unchanged * * Returns a font that is just like @font, but uses the - * given hinting options for its glyphs and metrics. + * given scale and hinting options for its glyphs and metrics. * * Returns: (transfer full): the modified `PangoFont` */ PangoFont * -gsk_get_hinted_font (PangoFont *font, - cairo_hint_style_t hint_style, - cairo_antialias_t antialias) +gsk_reload_font (PangoFont *font, + float scale, + cairo_hint_metrics_t hint_metrics, + cairo_hint_style_t hint_style, + cairo_antialias_t antialias) { cairo_font_options_t *options; cairo_scaled_font_t *sf; @@ -127,24 +51,32 @@ gsk_get_hinted_font (PangoFont *font, PangoFontDescription *desc; FcPattern *pattern; double dpi; + int size; #endif /* These requests often come in sequentially so keep the result * around and re-use it if everything matches. */ static PangoFont *last_font; + static float last_scale; + static cairo_hint_metrics_t last_hint_metrics; static cairo_hint_style_t last_hint_style; static cairo_antialias_t last_antialias; static PangoFont *last_result; if (last_result != NULL && last_font == font && + last_scale == scale && + last_hint_metrics == hint_metrics && last_hint_style == hint_style && last_antialias == antialias) return g_object_ref (last_result); + last_scale = scale; + last_hint_metrics = hint_metrics; last_hint_style = hint_style; last_antialias = antialias; + g_set_object (&last_font, font); g_clear_object (&last_result); @@ -152,15 +84,19 @@ gsk_get_hinted_font (PangoFont *font, sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font)); cairo_scaled_font_get_font_options (sf, options); + if (hint_metrics == CAIRO_HINT_METRICS_DEFAULT) + hint_metrics = cairo_font_options_get_hint_metrics (options); + if (hint_style == CAIRO_HINT_STYLE_DEFAULT) hint_style = cairo_font_options_get_hint_style (options); if (antialias == CAIRO_ANTIALIAS_DEFAULT) antialias = cairo_font_options_get_antialias (options); - if (cairo_font_options_get_hint_style (options) == hint_style && + if (1.0 == scale && + cairo_font_options_get_hint_metrics (options) == hint_metrics && + cairo_font_options_get_hint_style (options) == hint_style && cairo_font_options_get_antialias (options) == antialias && - cairo_font_options_get_hint_metrics (options) == CAIRO_HINT_METRICS_OFF && cairo_font_options_get_subpixel_order (options) == CAIRO_SUBPIXEL_ORDER_DEFAULT) { last_result = g_object_ref (font); @@ -168,9 +104,9 @@ gsk_get_hinted_font (PangoFont *font, return g_object_ref (font); } + cairo_font_options_set_hint_metrics (options, hint_metrics); cairo_font_options_set_hint_style (options, hint_style); cairo_font_options_set_antialias (options, antialias); - cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); cairo_font_options_set_subpixel_order (options, CAIRO_SUBPIXEL_ORDER_DEFAULT); if (!context) @@ -180,7 +116,7 @@ gsk_get_hinted_font (PangoFont *font, cairo_font_options_destroy (options); #if PANGO_VERSION_CHECK (1, 52, 0) - last_result = pango_font_map_reload_font (pango_font_get_font_map (font), font, 1.0, context, NULL); + last_result = pango_font_map_reload_font (pango_font_get_font_map (font), font, scale, context, NULL); #else pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font)); @@ -188,6 +124,13 @@ gsk_get_hinted_font (PangoFont *font, pango_cairo_context_set_resolution (context, dpi); desc = pango_font_describe (font); + size = pango_font_description_get_size (desc); + + if (pango_font_description_get_size_is_absolute (desc)) + pango_font_description_set_absolute_size (desc, size * scale); + else + pango_font_description_set_size (desc, (int) floor (size * scale + .5)); + last_result = pango_font_map_load_font (pango_font_get_font_map (font), context, desc); pango_font_description_free (desc); #endif @@ -213,9 +156,11 @@ gsk_get_unhinted_glyph_string_extents (PangoGlyphString *glyphs, { PangoFont *unhinted; - unhinted = gsk_get_hinted_font (font, - CAIRO_HINT_STYLE_NONE, - CAIRO_ANTIALIAS_DEFAULT); + unhinted = gsk_reload_font (font, + 1.0, + CAIRO_HINT_METRICS_OFF, + CAIRO_HINT_STYLE_NONE, + CAIRO_ANTIALIAS_DEFAULT); pango_glyph_string_extents (glyphs, unhinted, ink_rect, NULL); diff --git a/gsk/gskprivate.h b/gsk/gskprivate.h index 6c66431417..d9772e4e34 100644 --- a/gsk/gskprivate.h +++ b/gsk/gskprivate.h @@ -8,12 +8,11 @@ G_BEGIN_DECLS void gsk_ensure_resources (void); -PangoFont *gsk_get_scaled_font (PangoFont *font, - float scale); - -PangoFont *gsk_get_hinted_font (PangoFont *font, - cairo_hint_style_t hint_style, - cairo_antialias_t antialias); +PangoFont *gsk_reload_font (PangoFont *font, + float scale, + cairo_hint_metrics_t hint_metrics, + cairo_hint_style_t hint_style, + cairo_antialias_t antialias); void gsk_get_unhinted_glyph_string_extents (PangoGlyphString *glyphs, PangoFont *font, diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 0b66aacc75..e22a761ebd 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -2345,7 +2345,7 @@ parse_text_node (GtkCssParser *parser, g_assert (font); } - hinted = gsk_get_hinted_font (font, hint_style, antialias); + hinted = gsk_reload_font (font, 1.0, CAIRO_HINT_METRICS_OFF, hint_style, antialias); g_object_unref (font); font = hinted;