[pango/line-height: 5/5] Avoid recursion



commit a23adfa8bf4a3b5bf8e9e26313ad1b3722951e00
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jul 5 04:21:16 2019 +0000

    Avoid recursion
    
    In an evil twist, getting font metrics creates
    a layout to measure the average digit width -
    which in turn needs metrics to do its thing.
    
    This is only working by a lucky accident.
    Make it explicit.

 pango/pangocairo-font.c | 37 +++++++++++++++++++++++--------------
 pango/pangofc-font.c    | 46 ++++++++++++++++++++++++++++------------------
 2 files changed, 51 insertions(+), 32 deletions(-)
---
diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c
index 0769675b..7915be6f 100644
--- a/pango/pangocairo-font.c
+++ b/pango/pangocairo-font.c
@@ -224,6 +224,7 @@ _pango_cairo_font_get_metrics (PangoFont     *font,
   PangoCairoFontPrivate *cf_priv = PANGO_CAIRO_FONT_PRIVATE (font);
   PangoCairoFontMetricsInfo *info = NULL; /* Quiet gcc */
   GSList *tmp_list;
+  static int in_get_metrics;
 
   const char *sample_str = pango_language_get_sample_string (language);
 
@@ -300,29 +301,36 @@ _pango_cairo_font_get_metrics (PangoFont     *font,
          info->metrics->strikethrough_thickness *= xscale;
        }
 
-
       /* Set the matrix on the context so we don't have to adjust the derived
        * metrics. */
       pango_context_set_matrix (context, &pango_matrix);
 
-      /* Update approximate_*_width now */
-      layout = pango_layout_new (context);
-      desc = pango_font_describe_with_absolute_size (font);
-      pango_layout_set_font_description (layout, desc);
-      pango_font_description_free (desc);
+      /* Ugly. We need to prevent recursion when we call into
+       * PangoLayout to determine approximate char width.
+       */
+      if (!in_get_metrics)
+        {
+          in_get_metrics = 1;
 
-      pango_layout_set_text (layout, sample_str, -1);
-      pango_layout_get_extents (layout, NULL, &extents);
+          /* Update approximate_*_width now */
+          layout = pango_layout_new (context);
+          desc = pango_font_describe_with_absolute_size (font);
+          pango_layout_set_font_description (layout, desc);
+          pango_font_description_free (desc);
 
-      sample_str_width = pango_utf8_strwidth (sample_str);
-      g_assert (sample_str_width > 0);
-      info->metrics->approximate_char_width = extents.width / sample_str_width;
+          pango_layout_set_text (layout, sample_str, -1);
+          pango_layout_get_extents (layout, NULL, &extents);
 
-      pango_layout_set_text (layout, "0123456789", -1);
-      info->metrics->approximate_digit_width = max_glyph_width (layout);
+          sample_str_width = pango_utf8_strwidth (sample_str);
+          g_assert (sample_str_width > 0);
+          info->metrics->approximate_char_width = extents.width / sample_str_width;
 
-      g_object_unref (layout);
+          pango_layout_set_text (layout, "0123456789", -1);
+          info->metrics->approximate_digit_width = max_glyph_width (layout);
 
+          g_object_unref (layout);
+          in_get_metrics = 0;
+        }
 
       /* We may actually reuse ascent/descent we got from cairo here.  that's
        * in cf_priv->font_extents.
@@ -356,6 +364,7 @@ _pango_cairo_font_get_metrics (PangoFont     *font,
       g_object_unref (fontmap);
     }
 
+out:
   return pango_font_metrics_ref (info->metrics);
 }
 
diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c
index b8e8928a..79fb07c1 100644
--- a/pango/pangofc-font.c
+++ b/pango/pangofc-font.c
@@ -554,6 +554,7 @@ pango_fc_font_get_metrics (PangoFont     *font,
   PangoFcFont *fcfont = PANGO_FC_FONT (font);
   PangoFcMetricsInfo *info = NULL; /* Quiet gcc */
   GSList *tmp_list;
+  static int in_get_metrics;
 
   const char *sample_str = pango_language_get_sample_string (language);
 
@@ -579,6 +580,9 @@ pango_fc_font_get_metrics (PangoFont     *font,
 
       info = g_slice_new0 (PangoFcMetricsInfo);
 
+      /* Note: we need to add info to the list before calling
+       * into PangoLayout below, to prevent recursion
+       */
       fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang,
                                                 info);
 
@@ -589,29 +593,35 @@ pango_fc_font_get_metrics (PangoFont     *font,
 
       info->metrics = pango_fc_font_create_base_metrics_for_context (fcfont, context);
 
-      { /* Compute derived metrics */
-       PangoLayout *layout;
-       PangoRectangle extents;
-       const char *sample_str = pango_language_get_sample_string (language);
-       PangoFontDescription *desc = pango_font_describe_with_absolute_size (font);
-       gulong sample_str_width;
+      if (!in_get_metrics)
+        {
+          in_get_metrics = 1;
 
-        layout = pango_layout_new (context);
-       pango_layout_set_font_description (layout, desc);
-       pango_font_description_free (desc);
+          /* Compute derived metrics */
+          PangoLayout *layout;
+          PangoRectangle extents;
+          const char *sample_str = pango_language_get_sample_string (language);
+          PangoFontDescription *desc = pango_font_describe_with_absolute_size (font);
+          gulong sample_str_width;
 
-       pango_layout_set_text (layout, sample_str, -1);
-       pango_layout_get_extents (layout, NULL, &extents);
+          layout = pango_layout_new (context);
+          pango_layout_set_font_description (layout, desc);
+          pango_font_description_free (desc);
 
-       sample_str_width = pango_utf8_strwidth (sample_str);
-       g_assert (sample_str_width > 0);
-       info->metrics->approximate_char_width = extents.width / sample_str_width;
+          pango_layout_set_text (layout, sample_str, -1);
+          pango_layout_get_extents (layout, NULL, &extents);
 
-       pango_layout_set_text (layout, "0123456789", -1);
-       info->metrics->approximate_digit_width = max_glyph_width (layout);
+          sample_str_width = pango_utf8_strwidth (sample_str);
+          g_assert (sample_str_width > 0);
+          info->metrics->approximate_char_width = extents.width / sample_str_width;
 
-       g_object_unref (layout);
-      }
+          pango_layout_set_text (layout, "0123456789", -1);
+          info->metrics->approximate_digit_width = max_glyph_width (layout);
+
+          g_object_unref (layout);
+
+          in_get_metrics = 0;
+        }
 
       g_object_unref (context);
       g_object_unref (fontmap);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]