[gtksourceview/wip/chergert/snippets: 87/119] spacedrawer: port to GTK 4



commit 5cfb487be002963718634dd97568937e3473e3e4
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 15 14:28:00 2020 -0800

    spacedrawer: port to GTK 4
    
     - Use snapshot instead of cairo draw
     - Cache textures for better chance of reuse
     - Don't allocate a GdkRGBA, just track if it's set

 gtksourceview/gtksourcespacedrawer-private.h |   2 +-
 gtksourceview/gtksourcespacedrawer.c         | 270 ++++++++++++++++-----------
 2 files changed, 164 insertions(+), 108 deletions(-)
---
diff --git a/gtksourceview/gtksourcespacedrawer-private.h b/gtksourceview/gtksourcespacedrawer-private.h
index e7d3a5b4..62152e23 100644
--- a/gtksourceview/gtksourcespacedrawer-private.h
+++ b/gtksourceview/gtksourcespacedrawer-private.h
@@ -33,6 +33,6 @@ void _gtk_source_space_drawer_update_color (GtkSourceSpaceDrawer *drawer,
 GTK_SOURCE_INTERNAL
 void _gtk_source_space_drawer_draw         (GtkSourceSpaceDrawer *drawer,
                                             GtkSourceView        *view,
-                                            cairo_t              *cr);
+                                            GtkSnapshot          *snapshot);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcespacedrawer.c b/gtksourceview/gtksourcespacedrawer.c
index 51ed4219..15db7559 100644
--- a/gtksourceview/gtksourcespacedrawer.c
+++ b/gtksourceview/gtksourcespacedrawer.c
@@ -30,6 +30,7 @@
 #include "gtksourcebuffer.h"
 #include "gtksourcebuffer-private.h"
 #include "gtksourceiter-private.h"
+#include "gtksourcestylescheme.h"
 #include "gtksourcestylescheme-private.h"
 #include "gtksourcetag.h"
 #include "gtksourceview.h"
@@ -88,17 +89,41 @@
  * default with a DVD of Matrix, in case the astronauts are bored.
  */
 
-/*
-#define ENABLE_PROFILE
-*/
-#undef ENABLE_PROFILE
+#if 0
+# define ENABLE_PROFILE
+#else
+# undef ENABLE_PROFILE
+#endif
+
+typedef enum
+{
+       DRAW_TAB,
+       DRAW_NARROW_NBSP,
+       DRAW_NBSP,
+       DRAW_SPACE,
+       DRAW_NEWLINE,
+       N_DRAW
+} Draw;
+
+typedef struct
+{
+       GskRenderNode *node;
+       gint           width;
+       gint           height;
+} CachedNode;
 
 struct _GtkSourceSpaceDrawer
 {
-       GObject parent_instance;
+       GObject                  parent_instance;
+
        GtkSourceSpaceTypeFlags *matrix;
-       GdkRGBA *color;
-       guint enable_matrix : 1;
+
+       CachedNode               cached[N_DRAW];
+
+       GdkRGBA                  color;
+
+       guint                    color_set : 1;
+       guint                    enable_matrix : 1;
 };
 
 enum
@@ -113,6 +138,19 @@ static GParamSpec *properties[N_PROPERTIES];
 
 G_DEFINE_TYPE (GtkSourceSpaceDrawer, gtk_source_space_drawer, G_TYPE_OBJECT)
 
+static void
+gtk_source_space_drawer_purge_cache (GtkSourceSpaceDrawer *drawer)
+{
+       guint i;
+
+       g_return_if_fail (GTK_SOURCE_IS_SPACE_DRAWER (drawer));
+
+       for (i = 0; i < G_N_ELEMENTS (drawer->cached); i++)
+       {
+               g_clear_pointer (&drawer->cached[i].node, gsk_render_node_unref);
+       }
+}
+
 static gint
 get_number_of_locations (void)
 {
@@ -305,13 +343,9 @@ gtk_source_space_drawer_finalize (GObject *object)
 {
        GtkSourceSpaceDrawer *drawer = GTK_SOURCE_SPACE_DRAWER (object);
 
+       gtk_source_space_drawer_purge_cache (drawer);
        g_free (drawer->matrix);
 
-       if (drawer->color != NULL)
-       {
-               gdk_rgba_free (drawer->color);
-       }
-
        G_OBJECT_CLASS (gtk_source_space_drawer_parent_class)->finalize (object);
 }
 
@@ -706,11 +740,9 @@ _gtk_source_space_drawer_update_color (GtkSourceSpaceDrawer *drawer,
        g_return_if_fail (GTK_SOURCE_IS_SPACE_DRAWER (drawer));
        g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
 
-       if (drawer->color != NULL)
-       {
-               gdk_rgba_free (drawer->color);
-               drawer->color = NULL;
-       }
+       gtk_source_space_drawer_purge_cache (drawer);
+
+       drawer->color_set = FALSE;
 
        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
        style_scheme = gtk_source_buffer_get_style_scheme (buffer);
@@ -736,14 +768,15 @@ _gtk_source_space_drawer_update_color (GtkSourceSpaceDrawer *drawer,
                            color_str != NULL &&
                            gdk_rgba_parse (&color, color_str))
                        {
-                               drawer->color = gdk_rgba_copy (&color);
+                               drawer->color = color;
+                               drawer->color_set = TRUE;
                        }
 
                        g_free (color_str);
                }
        }
 
-       if (drawer->color == NULL)
+       if (!drawer->color_set)
        {
                GtkStyleContext *context;
                GdkRGBA color;
@@ -751,12 +784,11 @@ _gtk_source_space_drawer_update_color (GtkSourceSpaceDrawer *drawer,
                context = gtk_widget_get_style_context (GTK_WIDGET (view));
                gtk_style_context_save (context);
                gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
-               gtk_style_context_get_color (context,
-                                            gtk_style_context_get_state (context),
-                                            &color);
+               gtk_style_context_get_color (context, &color);
                gtk_style_context_restore (context);
 
-               drawer->color = gdk_rgba_copy (&color);
+               drawer->color = color;
+               drawer->color_set = TRUE;
        }
 }
 
@@ -806,61 +838,43 @@ is_whitespace (gunichar ch)
 }
 
 static void
-draw_space_at_pos (cairo_t      *cr,
-                   GdkRectangle  rect)
+draw_space_at_pos (cairo_t *cr,
+                   gdouble  w,
+                   gdouble  h)
 {
-       gint x, y;
-       gdouble w;
-
-       x = rect.x;
-       y = rect.y + rect.height * 2 / 3;
-
-       w = rect.width;
+       const gint x = 0;
+       const gint y = h * 2 / 3;
 
-       cairo_save (cr);
        cairo_move_to (cr, x + w * 0.5, y);
        cairo_arc (cr, x + w * 0.5, y, 0.8, 0, 2 * G_PI);
        cairo_stroke (cr);
-       cairo_restore (cr);
 }
 
 static void
-draw_tab_at_pos (cairo_t      *cr,
-                 GdkRectangle  rect)
+draw_tab_at_pos (cairo_t *cr,
+                 gdouble  w,
+                 gdouble  h)
 {
-       gint x, y;
-       gdouble w, h;
+       const gint x = 0;
+       const gint y = h * 2 / 3;
 
-       x = rect.x;
-       y = rect.y + rect.height * 2 / 3;
-
-       w = rect.width;
-       h = rect.height;
-
-       cairo_save (cr);
        cairo_move_to (cr, x + w * 1 / 8, y);
        cairo_rel_line_to (cr, w * 6 / 8, 0);
        cairo_rel_line_to (cr, -h * 1 / 4, -h * 1 / 4);
        cairo_rel_move_to (cr, +h * 1 / 4, +h * 1 / 4);
        cairo_rel_line_to (cr, -h * 1 / 4, +h * 1 / 4);
        cairo_stroke (cr);
-       cairo_restore (cr);
 }
 
 static void
-draw_newline_at_pos (cairo_t      *cr,
-                     GdkRectangle  rect)
+draw_newline_at_pos (cairo_t *cr,
+                     gdouble  w,
+                     gdouble  h)
 {
-       gint x, y;
-       gdouble w, h;
-
-       x = rect.x;
-       y = rect.y + rect.height / 3;
-
-       w = 2 * rect.width;
-       h = rect.height;
+       const gint x = 0;
+       const gint y = h / 3;
 
-       cairo_save (cr);
+       w = w * 2;
 
        if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR)
        {
@@ -882,48 +896,50 @@ draw_newline_at_pos (cairo_t      *cr,
        }
 
        cairo_stroke (cr);
-       cairo_restore (cr);
 }
 
 static void
-draw_nbsp_at_pos (cairo_t      *cr,
-                  GdkRectangle  rect,
-                  gboolean      narrowed)
+draw_narrow_nbsp_at_pos (cairo_t *cr,
+                         gdouble  w,
+                         gdouble  h)
 {
-       gint x, y;
-       gdouble w, h;
+       const gint x = 0;
+       const gint y = h / 2;
 
-       x = rect.x;
-       y = rect.y + rect.height / 2;
-
-       w = rect.width;
-       h = rect.height;
-
-       cairo_save (cr);
        cairo_move_to (cr, x + w * 1 / 6, y);
        cairo_rel_line_to (cr, w * 4 / 6, 0);
        cairo_rel_line_to (cr, -w * 2 / 6, +h * 1 / 4);
        cairo_rel_line_to (cr, -w * 2 / 6, -h * 1 / 4);
+       cairo_fill (cr);
+}
 
-       if (narrowed)
-       {
-               cairo_fill (cr);
-       }
-       else
-       {
-               cairo_stroke (cr);
-       }
+static void
+draw_nbsp_at_pos (cairo_t *cr,
+                  gdouble  w,
+                  gdouble  h)
+{
+       const gint x = 0;
+       const gint y = h / 2;
 
-       cairo_restore (cr);
+       cairo_move_to (cr, x + w * 1 / 6, y);
+       cairo_rel_line_to (cr, w * 4 / 6, 0);
+       cairo_rel_line_to (cr, -w * 2 / 6, +h * 1 / 4);
+       cairo_rel_line_to (cr, -w * 2 / 6, -h * 1 / 4);
+       cairo_stroke (cr);
 }
 
 static void
-draw_whitespace_at_iter (GtkTextView *text_view,
-                         GtkTextIter *iter,
-                         cairo_t     *cr)
+draw_whitespace_at_iter (GtkSourceSpaceDrawer *drawer,
+                         GtkTextView          *text_view,
+                         const GtkTextIter    *iter,
+                         const GdkRGBA        *color,
+                         GtkSnapshot          *snapshot)
 {
-       gunichar ch;
+       void (*draw) (cairo_t *cr, gdouble w, gdouble h) = NULL;
+       CachedNode *cache = NULL;
        GdkRectangle rect;
+       gunichar ch;
+       gint ratio = 1;
 
        gtk_text_view_get_iter_location (text_view, iter, &rect);
 
@@ -939,19 +955,66 @@ draw_whitespace_at_iter (GtkTextView *text_view,
 
        if (is_tab (ch))
        {
-               draw_tab_at_pos (cr, rect);
+               draw = draw_tab_at_pos;
+               cache = &drawer->cached[DRAW_TAB];
        }
        else if (is_nbsp (ch))
        {
-               draw_nbsp_at_pos (cr, rect, is_narrowed_nbsp (ch));
+               if (is_narrowed_nbsp (ch))
+               {
+                       draw = draw_narrow_nbsp_at_pos;
+                       cache = &drawer->cached[DRAW_NARROW_NBSP];
+               }
+               else
+               {
+                       draw = draw_nbsp_at_pos;
+                       cache = &drawer->cached[DRAW_NBSP];
+               }
        }
        else if (is_space (ch))
        {
-               draw_space_at_pos (cr, rect);
+               draw = draw_space_at_pos;
+               cache = &drawer->cached[DRAW_SPACE];
        }
        else if (is_newline (iter))
        {
-               draw_newline_at_pos (cr, rect);
+               draw = draw_newline_at_pos;
+               cache = &drawer->cached[DRAW_NEWLINE];
+               ratio = 2;
+       }
+
+       g_assert (draw == NULL || cache != NULL);
+
+       if (draw != NULL)
+       {
+               if (cache->width != rect.width || cache->height != rect.height)
+               {
+                       g_clear_pointer (&cache->node, gsk_render_node_unref);
+               }
+
+               if G_UNLIKELY (cache->node == NULL)
+               {
+                       GtkSnapshot *to_cache;
+                       cairo_t *cr;
+
+                       to_cache = gtk_snapshot_new ();
+                       cr = gtk_snapshot_append_cairo (to_cache,
+                                                       &GRAPHENE_RECT_INIT (0, 0, rect.width * ratio, 
rect.height));
+                       gdk_cairo_set_source_rgba (cr, color);
+                       cairo_set_line_width (cr, 0.8);
+                       cairo_translate (cr, -0.5, -0.5);
+                       draw (cr, rect.width, rect.height);
+                       cairo_destroy (cr);
+
+                       cache->node = gtk_snapshot_free_to_node (g_steal_pointer (&to_cache));
+                       cache->width = rect.width;
+                       cache->height = rect.height;
+               }
+
+               gtk_snapshot_save (snapshot);
+               gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (rect.x, rect.y));
+               gtk_snapshot_append_node (snapshot, cache->node);
+               gtk_snapshot_restore (snapshot);
        }
 }
 
@@ -1143,11 +1206,11 @@ get_line_end (GtkTextView       *text_view,
 void
 _gtk_source_space_drawer_draw (GtkSourceSpaceDrawer *drawer,
                                GtkSourceView        *view,
-                               cairo_t              *cr)
+                               GtkSnapshot          *snapshot)
 {
        GtkTextView *text_view;
        GtkTextBuffer *buffer;
-       GdkRectangle clip;
+       GdkRectangle visible;
        gint min_x;
        gint min_y;
        gint max_x;
@@ -1172,9 +1235,8 @@ _gtk_source_space_drawer_draw (GtkSourceSpaceDrawer *drawer,
 
        g_return_if_fail (GTK_SOURCE_IS_SPACE_DRAWER (drawer));
        g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
-       g_return_if_fail (cr != NULL);
 
-       if (drawer->color == NULL)
+       if (!drawer->color_set)
        {
                g_warning ("GtkSourceSpaceDrawer: color not set.");
                return;
@@ -1189,26 +1251,18 @@ _gtk_source_space_drawer_draw (GtkSourceSpaceDrawer *drawer,
                return;
        }
 
-       if (!gdk_cairo_get_clip_rectangle (cr, &clip))
-       {
-               return;
-       }
+       gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (view), &visible);
 
        is_wrapping = gtk_text_view_get_wrap_mode (text_view) != GTK_WRAP_NONE;
 
-       min_x = clip.x;
-       min_y = clip.y;
-       max_x = min_x + clip.width;
-       max_y = min_y + clip.height;
+       min_x = visible.x;
+       min_y = visible.y;
+       max_x = min_x + visible.width;
+       max_y = min_y + visible.height;
 
        gtk_text_view_get_iter_at_location (text_view, &start, min_x, min_y);
        gtk_text_view_get_iter_at_location (text_view, &end, max_x, max_y);
 
-       cairo_save (cr);
-       gdk_cairo_set_source_rgba (cr, drawer->color);
-       cairo_set_line_width (cr, 0.8);
-       cairo_translate (cr, -0.5, -0.5);
-
        iter = start;
        _gtk_source_iter_get_leading_spaces_end_boundary (&iter, &leading_end);
        _gtk_source_iter_get_trailing_spaces_start_boundary (&iter, &trailing_start);
@@ -1223,7 +1277,11 @@ _gtk_source_space_drawer_draw (GtkSourceSpaceDrawer *drawer,
                if ((is_whitespace (ch) || gtk_text_iter_is_end (&iter)) &&
                    space_needs_drawing (drawer, &iter, &leading_end, &trailing_start))
                {
-                       draw_whitespace_at_iter (text_view, &iter, cr);
+                       draw_whitespace_at_iter (drawer,
+                                                text_view,
+                                                &iter,
+                                                &drawer->color,
+                                                snapshot);
                }
 
                if (gtk_text_iter_is_end (&iter) ||
@@ -1276,8 +1334,6 @@ _gtk_source_space_drawer_draw (GtkSourceSpaceDrawer *drawer,
                }
        };
 
-       cairo_restore (cr);
-
 #ifdef ENABLE_PROFILE
        g_timer_stop (timer);
 


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