[gtk/text-rendering-fixes: 1/4] Redo font options handling




commit db1fc454ee4271adb82113878b6c7e76b49b6374
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Sep 4 09:35:20 2021 -0400

    Redo font options handling
    
    Avoid cairo types in the API by introducing a
    GskTextRenderFlags enum.

 gsk/gskenums.h                      |  26 +++++++
 gsk/gskprivate.c                    |  60 ++++++++++++++++
 gsk/gskprivate.h                    |   7 ++
 gsk/gskrendernode.h                 |  12 ++--
 gsk/gskrendernodeimpl.c             | 135 ++++++++++--------------------------
 gsk/ngl/gsknglglyphlibrary.c        |   5 +-
 gsk/ngl/gsknglglyphlibraryprivate.h |   6 +-
 gsk/ngl/gsknglrenderjob.c           |   9 +--
 gtk/gskpango.c                      |   6 +-
 gtk/gskpango.h                      |   2 +-
 gtk/gtksnapshot.c                   |  14 ++--
 gtk/gtksnapshotprivate.h            |  14 ++--
 12 files changed, 159 insertions(+), 137 deletions(-)
---
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 0dfeb0a0ea..01f89ca092 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -251,5 +251,31 @@ typedef enum
   GSK_GL_UNIFORM_TYPE_VEC4,
 } GskGLUniformType;
 
+/**
+ * GskTextRenderFlags:
+ * @GSK_TEXT_RENDER_NONE: No antialiasing or hinting
+ * @GSK_TEXT_RENDER_ANTIALIAS: Perform single-color antialiasing
+ * @GSK_TEXT_RENDER_HINT_METRICS: Hint font metrics
+ * @GSK_TEXT_RENDER_HINT_OUTLINES_SLIGHT: Hint outlines slightly to improve
+ *   contrast while retaining good fidelity to original shapes
+ * @GSK_TEXT_RENDER_HINT_OUTLINES_MEDIUM: Hint outlines with medium strength
+ *   giving a compromise between fidelity to the original shapes and contrast
+ * @GSK_TEXT_RENDER_HINT_OUTLINES_FULL: Hint outlines to maximize contrast
+ *
+ * The values of this enumerations describe how font outlines should
+ * be rendered.
+ *
+ * The value passed to [func@Gsk.text_node_new_with_render_flags] can be a
+ * combination of one of the outline values with the antialias and hint
+ * metrics flags.
+ */
+typedef enum {
+  GSK_TEXT_RENDER_NONE                 = 0,
+  GSK_TEXT_RENDER_ANTIALIAS            = 1 << 0,
+  GSK_TEXT_RENDER_HINT_METRICS         = 1 << 1,
+  GSK_TEXT_RENDER_HINT_OUTLINES_SLIGHT = 1 << 2,
+  GSK_TEXT_RENDER_HINT_OUTLINES_MEDIUM = 2 << 2,
+  GSK_TEXT_RENDER_HINT_OUTLINES_FULL   = 3 << 2,
+} GskTextRenderFlags;
 
 #endif /* __GSK_TYPES_H__ */
diff --git a/gsk/gskprivate.c b/gsk/gskprivate.c
index d9e1c3e30f..0af99eb385 100644
--- a/gsk/gskprivate.c
+++ b/gsk/gskprivate.c
@@ -35,3 +35,63 @@ pango_glyph_string_num_glyphs (PangoGlyphString *glyphs)
   return count;
 }
 
+GskTextRenderFlags
+gsk_text_render_flags_from_cairo (const cairo_font_options_t *options)
+{
+  GskTextRenderFlags flags = GSK_TEXT_RENDER_NONE;
+
+  if (cairo_font_options_get_antialias (options) != CAIRO_ANTIALIAS_NONE)
+    flags |= GSK_TEXT_RENDER_ANTIALIAS;
+
+  if (cairo_font_options_get_hint_metrics (options) == CAIRO_HINT_METRICS_ON)
+    flags |= GSK_TEXT_RENDER_HINT_METRICS;
+
+  switch (cairo_font_options_get_hint_style (options))
+    {
+    case CAIRO_HINT_STYLE_DEFAULT:
+    case CAIRO_HINT_STYLE_NONE:
+      break;
+    case CAIRO_HINT_STYLE_SLIGHT:
+      flags |= GSK_TEXT_RENDER_HINT_OUTLINES_SLIGHT;
+      break;
+    case CAIRO_HINT_STYLE_MEDIUM:
+      flags |= GSK_TEXT_RENDER_HINT_OUTLINES_MEDIUM;
+      break;
+    case CAIRO_HINT_STYLE_FULL:
+      flags |= GSK_TEXT_RENDER_HINT_OUTLINES_FULL;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  return flags;
+}
+
+void
+gsk_text_render_flags_to_cairo (GskTextRenderFlags    flags,
+                                cairo_font_options_t *options)
+{
+  cairo_font_options_set_hint_metrics (options, flags & GSK_TEXT_RENDER_HINT_METRICS
+                                                ? CAIRO_HINT_METRICS_ON
+                                                : CAIRO_HINT_METRICS_OFF);
+  cairo_font_options_set_antialias (options, flags & GSK_TEXT_RENDER_ANTIALIAS
+                                             ? CAIRO_ANTIALIAS_GRAY
+                                             : CAIRO_ANTIALIAS_NONE);
+  switch (flags & ~(GSK_TEXT_RENDER_ANTIALIAS | GSK_TEXT_RENDER_HINT_METRICS))
+    {
+    case GSK_TEXT_RENDER_NONE:
+      cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
+      break;
+    case GSK_TEXT_RENDER_HINT_OUTLINES_SLIGHT:
+      cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_SLIGHT);
+      break;
+    case GSK_TEXT_RENDER_HINT_OUTLINES_MEDIUM:
+      cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_MEDIUM);
+      break;
+    case GSK_TEXT_RENDER_HINT_OUTLINES_FULL:
+      cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+}
diff --git a/gsk/gskprivate.h b/gsk/gskprivate.h
index 5d9f88c942..1cc78bb124 100644
--- a/gsk/gskprivate.h
+++ b/gsk/gskprivate.h
@@ -1,8 +1,11 @@
 #ifndef __GSK_PRIVATE_H__
 #define __GSK_PRIVATE_H__
 
+#include "gskenums.h"
+
 #include <glib.h>
 #include <pango/pango.h>
+#include <cairo.h>
 
 G_BEGIN_DECLS
 
@@ -10,6 +13,10 @@ void gsk_ensure_resources (void);
 
 int pango_glyph_string_num_glyphs (PangoGlyphString *glyphs);
 
+GskTextRenderFlags gsk_text_render_flags_from_cairo (const cairo_font_options_t *options);
+void               gsk_text_render_flags_to_cairo   (GskTextRenderFlags          flags,
+                                                     cairo_font_options_t       *options);
+
 typedef struct _GskVulkanRender GskVulkanRender;
 typedef struct _GskVulkanRenderPass GskVulkanRenderPass;
 
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index c362ddb70c..0fa3e86b40 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -493,18 +493,14 @@ GskRenderNode *         gsk_text_node_new                       (PangoFont
                                                                  const GdkRGBA            *color,
                                                                  const graphene_point_t   *offset);
 GDK_AVAILABLE_IN_4_6
-GskRenderNode *         gsk_text_node_new_with_font_options     (const cairo_font_options_t *options,
-                                                                 PangoFont                  *font,
+GskRenderNode *         gsk_text_node_new_with_flags            (PangoFont                  *font,
                                                                  PangoGlyphString           *glyphs,
                                                                  const GdkRGBA              *color,
-                                                                 const graphene_point_t     *offset);
+                                                                 const graphene_point_t     *offset,
+                                                                 GskTextRenderFlags          flags);
 
 GDK_AVAILABLE_IN_4_6
-gboolean                gsk_text_node_get_hint_metrics          (const GskRenderNode      *node) G_GNUC_PURE;
-GDK_AVAILABLE_IN_4_6
-gboolean                gsk_text_node_get_antialias             (const GskRenderNode      *node) G_GNUC_PURE;
-GDK_AVAILABLE_IN_4_6
-cairo_hint_style_t      gsk_text_node_get_hint_style            (const GskRenderNode      *node) G_GNUC_PURE;
+GskTextRenderFlags      gsk_text_node_get_render_flags          (const GskRenderNode      *node) G_GNUC_PURE;
 GDK_AVAILABLE_IN_ALL
 PangoFont *             gsk_text_node_get_font                  (const GskRenderNode      *node) G_GNUC_PURE;
 GDK_AVAILABLE_IN_ALL
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 8a4c003a5a..4f5bf27b03 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -4337,9 +4337,7 @@ struct _GskTextNode
 
   PangoFont *font;
   guint has_color_glyphs : 1;
-  guint hint_metrics     : 1;
-  guint antialias        : 1;
-  guint hint_style       : 3;
+  guint render_flags     : 4;
 
   GdkRGBA color;
   graphene_point_t offset;
@@ -4375,9 +4373,7 @@ gsk_text_node_draw (GskRenderNode *node,
   cairo_save (cr);
 
   options = cairo_font_options_create ();
-  cairo_font_options_set_hint_metrics (options, self->hint_metrics ? CAIRO_HINT_METRICS_ON : 
CAIRO_HINT_METRICS_OFF);
-  cairo_font_options_set_antialias (options, self->antialias ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
-  cairo_font_options_set_hint_style (options, self->hint_style);
+  gsk_text_render_flags_to_cairo (self->render_flags, options);
   cairo_set_font_options (cr, options);
   cairo_font_options_destroy (options);
 
@@ -4435,12 +4431,32 @@ gsk_text_node_diff (GskRenderNode  *node1,
   gsk_render_node_diff_impossible (node1, node2, region);
 }
 
-static GskRenderNode *
-gsk_text_node_new_internal (const cairo_font_options_t *options,
-                            PangoFont                  *font,
-                            PangoGlyphString           *glyphs,
-                            const GdkRGBA              *color,
-                            const graphene_point_t     *offset)
+/**
+ * gsk_text_node_new_with_flags:
+ * @font: the `PangoFont` containing the glyphs
+ * @glyphs: the `PangoGlyphString` to render
+ * @color: the foreground color to render with
+ * @offset: offset of the baseline
+ * @flags: `GskTextRenderFlags`
+ *
+ * Creates a render node that renders the given glyphs.
+ *
+ * Note that @color may not be used if the font contains
+ * color glyphs.
+ *
+ * For best results, the @flags should match the cairo font
+ * options the were used to generated the @glyhs.
+ *
+ * Returns: (nullable) (transfer full) (type GskTextNode): a new `GskRenderNode`
+ *
+ * Since: 4.6
+ */
+GskRenderNode *
+gsk_text_node_new_with_flags (PangoFont                  *font,
+                              PangoGlyphString           *glyphs,
+                              const GdkRGBA              *color,
+                              const graphene_point_t     *offset,
+                              GskTextRenderFlags          flags)
 {
   GskTextNode *self;
   GskRenderNode *node;
@@ -4462,16 +4478,7 @@ gsk_text_node_new_internal (const cairo_font_options_t *options,
   self->color = *color;
   self->offset = *offset;
   self->has_color_glyphs = FALSE;
-  self->antialias = TRUE;
-  self->hint_style = CAIRO_HINT_STYLE_NONE;
-  self->hint_metrics = FALSE;
-
-  if (options)
-    {
-      self->antialias = cairo_font_options_get_antialias (options) != CAIRO_ANTIALIAS_NONE;
-      self->hint_metrics = cairo_font_options_get_hint_metrics (options) == CAIRO_HINT_METRICS_ON;
-      self->hint_style = cairo_font_options_get_hint_style (options);
-    }
+  self->render_flags = flags;
 
   glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo));
 
@@ -4502,32 +4509,6 @@ gsk_text_node_new_internal (const cairo_font_options_t *options,
   return node;
 }
 
-/**
- * gsk_text_node_new_with_font_options:
- * @options: `cairo_font_options_t` to render with
- * @font: the `PangoFont` containing the glyphs
- * @glyphs: the `PangoGlyphString` to render
- * @color: the foreground color to render with
- * @offset: offset of the baseline
- *
- * Creates a render node that renders the given glyphs.
- *
- * Note that @color may not be used if the font contains
- * color glyphs.
- *
- * Returns: (nullable) (transfer full) (type GskTextNode): a new `GskRenderNode`
- *
- * Since: 4.6
- */
-GskRenderNode *
-gsk_text_node_new_with_font_options (const cairo_font_options_t *options,
-                                     PangoFont                  *font,
-                                     PangoGlyphString           *glyphs,
-                                     const GdkRGBA              *color,
-                                     const graphene_point_t     *offset)
-{
-  return gsk_text_node_new_internal (options, font, glyphs, color, offset);
-}
 
 /**
  * gsk_text_node_new:
@@ -4549,68 +4530,26 @@ gsk_text_node_new (PangoFont              *font,
                    const GdkRGBA          *color,
                    const graphene_point_t *offset)
 {
-  return gsk_text_node_new_internal (NULL, font, glyphs, color, offset);
+  return gsk_text_node_new_with_flags (font, glyphs, color, offset,
+                                       GSK_TEXT_RENDER_ANTIALIAS);
 }
 
 /**
- * gsk_text_node_get_hint_metrics:
+ * gsk_text_node_get_render_flags:
  * @node: (type GskTextNode): a text `GskRenderNode`
  *
- * Retrieves whether metrics hinting is enabled for rendering.
- *
- * See the cairo 
[documentation](https://www.cairographics.org/manual/cairo-cairo-font-options-t.html#cairo-hint-metrics-t).
- *
- * Returns: whether metrics hinting is enabled
- *
- * Since: 4.6
- */
-gboolean
-gsk_text_node_get_hint_metrics (const GskRenderNode *node)
-{
-  const GskTextNode *self = (const GskTextNode *) node;
-
-  return self->hint_metrics;
-}
-
-/**
- * gsk_text_node_get_antialias:
- * @node: (type GskTextNode): a text `GskRenderNode`
- *
- * Retrieves whether antialiasing is enabled for rendering.
- *
- * See the cairo [documentation](https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-antialias-t).
- * Note that GSK only supports grayscale antialiasing.
- *
- * Returns: whether antialiasing is enabled
- *
- * Since: 4.6
- */
-gboolean
-gsk_text_node_get_antialias (const GskRenderNode *node)
-{
-  const GskTextNode *self = (const GskTextNode *) node;
-
-  return self->antialias;
-}
-
-/**
- * gsk_text_node_get_hint_style:
- * @node: (type GskTextNode): a text `GskRenderNode`
- *
- * Retrieves what style of font hinting is used for rendering.
- *
- * See the cairo 
[documentation](https://www.cairographics.org/manual/cairo-cairo-font-options-t.html#cairo-hint-style-t).
+ * Retrieves render flags for @node.
  *
- * Returns: what style of hinting is used
+ * Returns: the render flags
  *
  * Since: 4.6
  */
-cairo_hint_style_t
-gsk_text_node_get_hint_style (const GskRenderNode *node)
+GskTextRenderFlags
+gsk_text_node_get_render_flags (const GskRenderNode *node)
 {
   const GskTextNode *self = (const GskTextNode *) node;
 
-  return self->hint_style;
+  return self->render_flags;
 }
 
 /**
diff --git a/gsk/ngl/gsknglglyphlibrary.c b/gsk/ngl/gsknglglyphlibrary.c
index fdfa1abe30..1db36aeece 100644
--- a/gsk/ngl/gsknglglyphlibrary.c
+++ b/gsk/ngl/gsknglglyphlibrary.c
@@ -172,10 +172,9 @@ render_glyph (cairo_surface_t           *surface,
   g_assert (scaled_font != NULL);
 
   cr = cairo_create (surface);
+
   options = cairo_font_options_create ();
-  cairo_font_options_set_hint_metrics (options, key->hint_metrics ? CAIRO_HINT_METRICS_ON : 
CAIRO_HINT_METRICS_OFF);
-  cairo_font_options_set_antialias (options, key->antialias ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
-  cairo_font_options_set_hint_style (options, key->hint_style);
+  gsk_text_render_flags_to_cairo (key->render_flags, options);
   cairo_set_font_options (cr, options);
   cairo_font_options_destroy (options);
 
diff --git a/gsk/ngl/gsknglglyphlibraryprivate.h b/gsk/ngl/gsknglglyphlibraryprivate.h
index 6d9e81060e..90aaa191ee 100644
--- a/gsk/ngl/gsknglglyphlibraryprivate.h
+++ b/gsk/ngl/gsknglglyphlibraryprivate.h
@@ -35,10 +35,8 @@ typedef struct _GskNglGlyphKey
   PangoGlyph glyph;
   guint xshift : 2;
   guint yshift : 2;
-  guint hint_metrics : 1;
-  guint antialias : 1;
-  guint hint_style : 3;
-  guint scale  : 23; /* times 1024 */
+  guint render_flags : 4;
+  guint scale  : 24; /* times 1024 */
 } GskNglGlyphKey;
 
 typedef struct _GskNglGlyphValue
diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c
index 719b9da0dc..b6d1afe826 100644
--- a/gsk/ngl/gsknglrenderjob.c
+++ b/gsk/ngl/gsknglrenderjob.c
@@ -2875,15 +2875,12 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob     *job,
 
   rgba_to_half (color, cc);
 
-  /* We have 23 bits in the key for the scale */
-  g_assert (text_scale * 1024 < (1 << 24));
+  /* We have 24 bits in the key for the scale */
+  g_assert (text_scale * 1024 < (1 << 25));
 
   lookup.font = (PangoFont *)font;
   lookup.scale = (guint) (text_scale * 1024);
-
-  lookup.hint_metrics = gsk_text_node_get_hint_metrics (node);
-  lookup.antialias = gsk_text_node_get_antialias (node);
-  lookup.hint_style = gsk_text_node_get_hint_style (node);
+  lookup.render_flags = gsk_text_node_get_render_flags (node);
 
   yshift = compute_phase_and_pos (y, &ypos);
 
diff --git a/gtk/gskpango.c b/gtk/gskpango.c
index 93aba75f60..86e3f097a4 100644
--- a/gtk/gskpango.c
+++ b/gtk/gskpango.c
@@ -100,12 +100,12 @@ gsk_pango_renderer_draw_glyph_item (PangoRenderer  *renderer,
   get_color (crenderer, PANGO_RENDER_PART_FOREGROUND, &color);
 
   gtk_snapshot_append_text (crenderer->snapshot,
-                            crenderer->options,
                             glyph_item->item->analysis.font,
                             glyph_item->glyphs,
                             &color,
                             (float) x / PANGO_SCALE,
-                            (float) y / PANGO_SCALE);
+                            (float) y / PANGO_SCALE,
+                            crenderer->render_flags);
 }
 
 static void
@@ -479,7 +479,7 @@ gtk_snapshot_append_layout (GtkSnapshot   *snapshot,
 
   crenderer->snapshot = snapshot;
   crenderer->fg_color = color;
-  crenderer->options = pango_cairo_context_get_font_options (context);
+  crenderer->render_flags = gsk_text_render_flags_from_cairo (pango_cairo_context_get_font_options 
(context));
 
   pango_renderer_draw_layout (PANGO_RENDERER (crenderer), layout, 0, 0);
 
diff --git a/gtk/gskpango.h b/gtk/gskpango.h
index 05fa2254a0..3506bc3f81 100644
--- a/gtk/gskpango.h
+++ b/gtk/gskpango.h
@@ -63,7 +63,7 @@ struct _GskPangoRenderer
   /* Error underline color for this widget */
   GdkRGBA               *error_color;
 
-  const cairo_font_options_t  *options;
+  GskTextRenderFlags     render_flags;
 
   GskPangoRendererState  state;
 
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index b8d0968c8f..0874df7f64 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -2122,23 +2122,23 @@ gtk_snapshot_render_layout (GtkSnapshot     *snapshot,
 
 void
 gtk_snapshot_append_text (GtkSnapshot                *snapshot,
-                          const cairo_font_options_t *options,
                           PangoFont                  *font,
                           PangoGlyphString           *glyphs,
                           const GdkRGBA              *color,
                           float                       x,
-                          float                       y)
+                          float                       y,
+                          GskTextRenderFlags          flags)
 {
   GskRenderNode *node;
   float dx, dy;
 
   gtk_snapshot_ensure_translate (snapshot, &dx, &dy);
 
-  node = gsk_text_node_new_with_font_options (options,
-                                              font,
-                                              glyphs,
-                                              color,
-                                              &GRAPHENE_POINT_INIT (x + dx, y + dy));
+  node = gsk_text_node_new_with_flags (font,
+                                       glyphs,
+                                       color,
+                                       &GRAPHENE_POINT_INIT (x + dx, y + dy),
+                                       flags);
   if (node == NULL)
     return;
 
diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h
index ca32df1a52..2f3b9b32c8 100644
--- a/gtk/gtksnapshotprivate.h
+++ b/gtk/gtksnapshotprivate.h
@@ -24,13 +24,13 @@
 
 G_BEGIN_DECLS
 
-void                    gtk_snapshot_append_text                (GtkSnapshot                *snapshot,
-                                                                 const cairo_font_options_t *options,
-                                                                 PangoFont                  *font,
-                                                                 PangoGlyphString           *glyphs,
-                                                                 const GdkRGBA              *color,
-                                                                 float                       x,
-                                                                 float                       y);
+void                    gtk_snapshot_append_text                (GtkSnapshot            *snapshot,
+                                                                 PangoFont              *font,
+                                                                 PangoGlyphString       *glyphs,
+                                                                 const GdkRGBA          *color,
+                                                                 float                   x,
+                                                                 float                   y,
+                                                                 GskTextRenderFlags      flags);
 
 void                    gtk_snapshot_push_collect               (GtkSnapshot            *snapshot);
 GskRenderNode *         gtk_snapshot_pop_collect                (GtkSnapshot            *snapshot);


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